How do I do cross-entity server-side validation - validation

In my application, I have cross-entity validation logic that requires me to look at the entire change set and I'm doing this using the BeforeSaveEntities override.
I can construct the right logic by examining the saveMap parameter, but what am I supposed to do if I find something invalid?
If I throw an exception, like I would for single entity validation in the BeforeSaveEntity override, the whole save is aborted and the error is reported to the client. But some of the entities might be valid so I would want to save those and only abort the invalid parts.
Because BeforeSaveEntities returns a saveMap, I think I should be able to remove the invalid entities from the change set and continue to save the valid entities, but then how do I report the invalid parts to the client?
Is it possible to do a partial save of only the valid entities and at the same time, report a sensible error to the client to describe the parts of the save that failed?

Jay told you the way it is.
I wouldn't hold my breath waiting for Breeze to change because I think yours is a rare scenario and it isn't one we would want to encourage anyway.
But I'm weird and I can't stop thinking what I'd do if were you and I absolutely HAD to do it. I might try something like this.
Warning: this is pseudo-code and I'm making this up. I do not recommend or warrant this
Create a custom MyCustomEFContextProvider that derives from EFContextProvider.
Give it an ErrorEntities property to hold the error object
Override (shadow) the SaveChanges method with another that delegates to the base
public new CustomSaveResult SaveChanges(JObject saveBundle,
TransactionSettings transactionSettings = null) {
var result = base.SaveChanges(saveBundle, transactionSettings);
// learn about CustomSaveResult below
return new CustomSaveResult(this.ErrorEntities, result);
}
Catch an invalid entity inside BeforeSaveEntities
Pass it with error message to your custom ErrorEntities property
You get to that property via the EntityInfo instance as in
((MyCustomEFContextProvider) info.ContextProvider).ErrorEntities.Add(new ErrorEntity(info, message));
Remove the invalid entity from the SaveMap so it won't be included in the actual save
Let the save continue
The second line of your override SaveChanges method creates a new instance of your CustomSaveResult from the standard one and returns that to the caller.
public class CustomSaveResult : SaveResult {
public List ErrorEntities;
public CustomSaveResult(List errorEntities, SaveResult result){
// copy over everything
this.Entities = result.Entities;
this.KeyMappings = result.KeyMappings;
this.Errors = this.Errors;
// and now your error stuff
this.ErrorEntities = errorEntities;
}
}
Let's assume the caller is your Web API controller's SaveChanges method. Well you don't have to change a thing but you might make it clear by explicitly returning your custom SaveResult:
readonly MyCustomEFContextProvider _contextProvider = new MyCustomEFContextProvider();
...
[HttpPost]
public CustomSaveResult SaveChanges(JObject saveBundle) {
return _contextProvider.SaveChanges(saveBundle);
}
JSON.Net will happily serialize the usual material + your custom ErrorEntities property (be sure to make it serializable!) and send it to the Breeze client.
On the Breeze client you write your own variation on the stock Breeze Web API data service adapter. Yours does almost exactly the same thing as the Breeze version. But, when processing the save payload from the server, it also extracts this extra "error entities" material in the response and does whatever you want to do with it.
I don't know what that will be but now you have it.
See how easy that was? LOL.

Breeze does not currently support a save mechanism that both saves and returns an error at the same time. While possible this seems a bit baroque.
As you pointed out, you can
1) Throw an exception inside of the BeforeSaveEntities and fail the save. You can even specify which specific entity or entities caused the failure and why. In this case the entire save is aborted.
or
2) Remove 'bad' items from the saveMap within the BeforeSaveEntities and save only a subset of what was passed in. In this case you are performing a partial save.
But we don't support a hybrid of these two. Please add this to the Breeze User Voice if you feel strongly and we can see if other members of the community feel that this would be useful.

Related

Getting the content from a MailMessage object

I am trying to create a system that will automatically log the content of any email notifications that my site sends to users, against their accounts.
I am doing this by listening for the NotificationSent event, which provides me with easy access to the Notifiable (the object that I want to store my log entry against) and the Notification (the object that defined the message that has been sent).
Using these I am able to get hold of the MailMessage object, but I can't work out how to render it. I was hoping it would have a render method but I can't find one. Presumably there is some other object that takes the MailMessage and does the rendering. Any clues?
Ideally I'd like the plain text version of the email (the markdown)
Thanks for any help
I've got a solution that is doing what I want. I cannibalised some code I wrote for something else, that got me a long way there. There are some steps that I don't completely understand so there may well be some unnecessary bloat in here:
class LogNotification
{
public function handle(NotificationSent $event)
{
//getting the MailMessage object
$mailMsg = $event->notification->toMail($event->notifiable);
//I think this is getting the additional variables from the
//MailMessage that are needed to render the view
$msgData = array_merge($mailMsg->toArray(),$mailMsg->viewData);
//I don't fully understand this. I get that the Markdown object is
//going to do the rendering, but I don't know why it needs to be
//instantiated with an empty View object
$markdown = new \Illuminate\Mail\Markdown(view(), config('mail.markdown'));
//Pass the renderText method the path to the markdown, and the message data
$msgContent = $markdown->renderText($mailMsg->markdown, $msgData);
}
}
Hopefully this is helpful to someone (and if anyone can offer a proper explanation of what is happening when the Markdown object is instantiated, I'd be grateful).

Grails: object is being saved although it has errors

I'm having a problem while trying to validate and save domain object.
First I'm making the validation, when the validation is wrong, I'm putting error inside my future to be saved object, like this:
myDomain.errors.reject("An Error")
myDomain.discard()
Then, when I'm trying to save this object, I can see that error list has one error but 'validate()' returns 'true', also, when the function is finished the object is being saved automatically.
I must say that all the called functions are in the same class which is a controller.
I need to know how to code my save function (in the controller class) which shows only the error without saving the object, and when the validation is good, to save the object.
Thanks!
myDomain.validate() will overwrite myDomain.errors clearing the reject(). You could do something like this:
// bind etc.
...
// do grails validation
if (!myDomain.validate()) {
myDomain.discard()
}
// do custom validation
if (custom validation has errors) {
myDomain.errors.reject ()
myDomain.discard()
}
If you can move you custom validation into a validator on myDomain you do not need the custom validation.
You don't need to call save() explicitly.
The fix was to use:
#Transactional(readOnly = true)
For the function which located in the service file.
It makes the function to avoid from saving transactions in the end of it, which caused the problem in the first place.

Implementing thread-safe, parallel processing

I am trying to convert an existing process in a way that it supports multi-threading and concurrency to make the solution more robust and reliable.
Take the example of an emergency alert system. When a worker clocks-in, a new Recipient object is created with their information and added to the Recipients collection. Conversely, when they clock-out, the object is removed. And in the background, when an alert occurs, the alert engine will iterate through the same list of Recipients (foreach), calling SendAlert(...) on each object.
Here are some of my requirements:
Adding a recipient should not block if an alert is in progress.
Removing a recipient should not block if an alert is in progress.
Adding or removing a recipient should not affect the list of
recipients used by an in-progress alert.
I've been looking at the Task and Parallel classes as well as the BlockingCollection and ConcurrentQueue classes but am not clear what the best approach is.
Is it as simple as using a BlockingCollection? After reading a ton of documentation, I'm still not sure what happens if Add is called while I am enumerating the collection.
UPDATE
A collegue referred me to the following article which describes the ConcurrentBag class and how each operation behaves:
http://www.codethinked.com/net-40-and-system_collections_concurrent_concurrentbag
Based on the author's explanation, it appears that this collection will (almost) serve my purposes. I can do the following:
Create a new collection
var recipients = new ConcurrentBag();
When a worker clocks-in, create a new Recipient and add it to the collection:
recipients.Add(new Recipient());
When an alert occurs, the alert engine can iterate through the collection at that time because GetEnumerator uses a snapshot of the collection items.
foreach (var recipient in recipients)
recipient.SendAlert(...);
When a worker clocks-out, remove the recipient from the collection:
???
The ConcurrentBag does not provide a way to remove a specific item. None of the concurrent classes do as far as I can tell. Am I missing something? Aside from this, ConcurrentBag does everything I need.
ConcurrentBag<T> should definitely be the best performing class out of the bunch for you to use for such a case. Enumeration works exactly as your friend describes and so it should serve well for the scenario you have laid out. However, knowing you have to remove specific items from this set, the only type that's going to work for you is ConcurrentDictionary<K, V>. All the other types only offer a TryTake method which, in the case of ConcurrentBag<T>, is indeterminate or, in the case of ConcurrentQueue<T> or ConcurrentStack<T> ordered only.
For broadcasting you would just do:
ConcurrentDictionary<string, Recipient> myConcurrentDictionary = ...;
...
foreach(Recipient recipient in myConcurrentDictionary.Values)
{
...
}
The enumerator is once again a snapshot of the dictionary in that instant.
I came into work this morning to an e-mail from a friend that gives me the following two answers:
1 - With regards to how the collections in the Concurrent namespace work, most of them are designed to allow additions and subtractions from the collection without blocking and are thread-safe even when in the process of enumerating the collection items.
With a "regular" collection, getting an enumerator (via GetEnumerator) sets a "version" value that is changed by any operation that affects the collection items (such as Add, Remove or Clear). The IEnumerator implementation will compare the version set when it was created against the current version of the collection. If different, an exception is thrown and enumeration ceases.
The Concurrent collections are designed using segments that make it very easy to support multi-threading. But, in the case of enumerating, they actually create a snapshot copy of the collection at the time GetEnumerator is called and the enumerator works against this copy. That allows changes to be made to the collection without adverse affects on the enumerator. Of course this means that the enumeration will know nothing of these changes but it sounds like your use-case allows this.
2 - As far as the specific scenario you are describing, I don't believe that a Concurrent collection is needed. You can wrap a standard collection using a ReaderWriterLock and apply the same logic as the Concurrent collections when you need to enumerate.
Here's what I suggest:
public class RecipientCollection
{
private Collection<Recipient> _recipients = new Collection<Recipient>();
private ReaderWriterLock _lock = new ReaderWriterLock();
public void Add(Recipient r)
{
_lock.AcquireWriterLock(Timeout.Infinite);
try
{
_recipients.Add(r);
}
finally
{
_lock.ReleaseWriterLock();
}
}
public void Remove(Recipient r)
{
_lock.AcquireWriterLock(Timeout.Infinite);
try
{
_recipients.Remove(r);
}
finally
{
_lock.ReleaseWriterLock();
}
}
public IEnumerable<Recipient> ToEnumerable()
{
_lock.AcquireReaderLock(Timeout.Infinite);
try
{
var list = _recipients.ToArray();
return list;
}
finally
{
_lock.ReleaseReaderLock();
}
}
}
The ReaderWriterLock ensures that operations are only blocked if another operation that changes the collection's contents is in progress. As soon as that operation completes, the lock is released and the next operation can proceed.
Your alert engine would use the ToEnumerable() method to obtain a snapshot copy of the collection at that time and enumerate the copy.
Depending on how often an alert is sent and changes are made to the collection, this could be an issue but you might be able to still implement some type of version property that is changed when an item is added or removed and the alert engine can check this property to see if it needs to call ToEnumerable() again to get the latest version. Or encapsulate this by caching the array inside the RecipientCollection class and invalidating the cache when an item is added or removed.
HTH
There is much more to an implementation like this than just the parallel processing aspects, durability probably being paramount among them. Have you considered building this using an existing PubSub technology like say... Azure Topics or NServiceBus?
Your requirements strike me as an good fit for the way standard .NET events are triggered in C#. I don't know offhand if the VB syntax gets compiled to similar code or not. The standard pattern looks something like:
public event EventHandler Triggered;
protected void OnTriggered()
{
//capture the list so that you don't see changes while the
//event is being dispatched.
EventHandler h = Triggered;
if (h != null)
h(this, EventArgs.Empty);
}
Alternatively, you could use an immutable list class to store the recipients. Then when the alert is sent, it will first take the current list and use it as a "snapshot" that cannot be modified by adding and removing while you are sending the alert. For example:
class Alerter
{
private ImmutableList<Recipient> recipients;
public void Add(Recipient recipient)
{
recipients = recipients.Add(recipient);
}
public void Remove(Recipient recipient)
{
recipients = recipients.Remove(recipient);
}
public void SendAlert()
{
//make a local reference to the current list so
//you are not affected by any calls to Add/Remove
var current = recipients;
foreach (var r in current)
{
//send alert to r
}
}
}
You will have to find an implementation of an ImmutableList, but you should be able to find several without too much work. In the SendAlert method as I wrote it, I probably didn't need to make an explicit local to avoid problems as the foreach loop would have done that itself, but I think the copy makes the intention clearer.

How to change a single querystring parameter, possibly via a control action?

In the last three days I've struggled trying to find a way to accomplish what I though was supposed to be a simple thing. Doing this on my own or searching for a solution in the web, didn't help. Maybe because I'm not even sure what to look for, when I do my researches.
I'll try to explain as much as I can here: maybe someone will be able to help me.
I won't say how I'm doing it, because I've tried to do it in many ways and none of them worked for different reasons: I prefer to see a fresh advice from you.
In most of the pages of web application, I have two links (but they could be more) like that:
Option A
Option B
This is partial view, retured by a controller action.
User can select or both (all) values, but they can't never select none of them: meaning that at least one must be always selected.
These links must che accessible in almost all pages and they are not supposed to redirect to a different page, but only to store this information somewhere, to be reused when action needs to filter returned contents: a place always accessible, regarding the current controller, action or user (including non authenticated users) (session? cookie?).
This information is used to filter displayed contents in the whole web application.
So, the problem is not how to create the business logi of that, but how (and where) to store this information:
without messing with the querystring (means: keeps the querystring as empty/clean as possible)
without redirecting to other pages (user must get the current page, just with different contents)
allow this information to persists between all views, until user click again to change the option(s)
My aim is to have this information stored in a model that will contains all options and their selection status (on/off), so the appropriates PartialView will know how to display them.
Also, I could send this model to the "thing" that will handle option changes.
Thanks.
UPDATE
Following Paul's advice, I've took the Session way:
private List<OptionSelectionModel> _userOptionPreferences;
protected List<OptionSelectionModel> UserOptionPreferences
{
get
{
if (Session["UserOptionPreferences"] == null)
{
_userOptionPreferences= Lib.Options.GetOptionSelectionModelList();
}
else
{
_userOptionPreferences= Session["UserOptionPreferences"].ToString().Deserialize<List<OptionSelectionModel>>();
}
if (_userOptionPreferences.Where(g => g.Selected).Count() == 0)
{
foreach (var userOptionPreferencesin _userOptionPreferences)
{
userOptionPreferences.Selected = true;
}
}
UserOptionPreferences= _userOptionPreferences;
return _userOptionPreferences;
}
private set
{
_userOptionPreferences= value;
Session["UserOptionPreferences"] = _userOptionPreferences.SerializeObject();
}
}
Following this, I've overridden (not sure is the right conjugation of "to override" :) OnActionExecuting():
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
GetOptionSelections();
base.OnActionExecuting(filterContext);
}
GetOptionSelections()...
private void GetOptionSelections()
{
if (String.IsNullOrEmpty(Request["optionCode"])) return;
var newOptionCode = Request["optionCode "];
foreach (var userOptionPreferencesin UserOptionPreferences)
{
if (userOptionPreferences.OptionCode == newOptionCode )
userOptionPreferences.Selected = !userOptionPreferences.Selected;
}
}
This code I think can be better, but right now I just want to make it work and it doesn't.
Maybe there are also other issues there (quite sure, actually), but I believe the main issue is that OnActionExecuting is called by each action in a controller that inherit from BaseController, therefore it keeps toggling userOptionPreferences.Selected on/off, but I don't know how to make GetOptionSelections() being called only once in each View: something like the old Page_Load, but for MVC.
Last update AKA solution
Ok, using the session way, I've managed to store this information.
The other issue wasn't really on topic with this question and I've managed to solve it creating a new action that take cares of handling the option's change, then redirects to the caller URL (using the usual returnUrl parameter, but as action parameter).
This way, the option change is done only once per call.
The only thing I don't really like is that I can't simply work with the UserOptionPreferences property, as it doesn't change the session value, but only the value in memory, so I have to set the property with the new object's status each time: not a big deal, but not nice either.
This is a place to use session.
The session will keep your setting between requests while keeping it out of the url querystring. It seems that you have probably tried this already, but try it again and if you have problems ask again. I think it will be the best way for you to solve this problem.

Updating LINQ to SQL object causing System.NotSupportedException

I get System.NotSupportedException: An attempt has been made to Attach or Add an entity that is not new perhaps having been loaded from another DataContext when I want to update an object's with child entities.
The scenario is like this:
I have a SubscriberProvider that allows me to create subscribers.
var provider = new SubscriberProvider(); // Creates a new repository with own datacontext
var newSubscriber = new Subscriber
{
EmailAddress = emailAddress,
};
newSubscriber.Interests.Add(new Interest{
Id=1,
Name="cars"
});
provider.Subscribe(newSubscriber);
On a normal subscribe page, this works fine.
Now I have a linq2sql Member class(retrievable by a MemberRepository) and I want to extend it to have a helper subscribe method like so:
var repository = new MembershipRepository(); // Holds its own datacontext
var member = repository.Get("member1");
member.Subscribe(); // transfer member's info and interests to subscriber's table
The exception occurs when SubscriberProvider tries to add interests of the member.
Commenting out
newSubscriber.Interests.Add(new Interest{
Id=1,
Name="cars"
});
will make member.Subscribe() work.
member.Subscribe() is simply:
public void Subscribe(bool emailIsVerified, bool receiveEmails, bool sendDoubleOptIn)
{
var provider = new MailingListProvider();
provider.Subscribe(EmailAddress, emailIsVerified, receiveEmails, CountryId, sendDoubleOptIn, ConvertInterests(MemberInterests.ToList()));
}
So what's causing the child entities(Interests) to lose their datacontext when I do member.Subscribe() and how do I go about fixing this?
It seems there's some code missing here, but I'll take a stab anyway because I think I have an idea what's going on.
If you have a different DataContext created for your MembershipRepository and your SubscriberRepository you're going to have issues related to entities "having been loaded from another DataContext." (as the Exception you posted points out). You can't just take an object out of one DataContext and save it into another.
It seems that you might have an architectural issue here. Should these 2 repositories actually be separate? If so, should they have completely different DataContexts? I would probably recommend using Dependency Injection to inject your DataContexts into your Repositories. Then you can decide how to cache your DataContexts.
That line of code you commented out is being flagged by the DataContext as a new record, even though it's likely that the record already exists, due to the error message.
Change the line to:
newSubscriber.Interests.Add(DataContext.Interests.Where(a => a.Id == 1).Single());
Now, the DataContext will know that record is one that already exists, and won't try to add it as an Insert to the ChangeSet.
Found the solution to this myself. Turns out it was the ConvertInterests() method causing it. The converted interest object had an invalid declaration which compiled ok.
Thinking the code was simple enough, I didn't create a test for it. I should have known better!

Resources