LINQ to SQL partial class OnValidate Changeaction.Delete - asp.net

I have a LINQ partial class:
public partial class resp
{
public IEnumerable<RuleViolation> GetRuleViolations()
{
if (String.IsNullOrEmpty(respName))
yield return new RuleViolation("Responsibility name required", "respName");
yield break;
}
public bool IsValid
{
// Quick method for checking to see whether an object contains any RuleViolations
get { return (GetRuleViolations().Count() == 0); }
}
partial void OnValidate(ChangeAction action)
{
// Hook to LINQ to be notified before db is actually persisted .. and check to make sure resp is not used by respApprover or approvals
if (action == ChangeAction.Delete && ((respApprovers.Count() != 0 || approvals.Count() != 0)))
throw new ApplicationException("You cannot delete a responsibility that is in use");
if (!IsValid)
throw new ApplicationException("Rule violations prevent saving");
}
}
In my code I would like to be able to check whether a responsibility (dbo.resp) exists before it is deleted.
I am accomplishing this check with a hook to OnValidate as above ... if (action == ChangeAction.Delete) ... and returning an application exception if it fails.
Also, during normal validation, I would like to check to make sure rule violations aren't made (resp.respName in this case...)
So, normally I can just do a try { } catch { var errors = resps.GetRuleViolations() } and check whether I have validation errors. Of course, that doesn't know what action is being taken (Changeaction.Delete)
I guess my main question is, how can I have OnValidate return a reason rather than crash my whole app when the Changeaction is delete. Normally I would catch GetRuleViolations but if I put the 'if statement' in the GetRuleViolations ... it will always be true even during checks to see if the data was correct (in other words, respApprovers.Count() will matter even for checks on new insertions which I don't want to. I only want those count checks to be made on deletion)
Or possibly more simply stated: I want GetRuleViolations to tell me when someone attempts to delete resp that has respApprovers.Count() > 0 or approvals.Count() > 0 but only when the OnValidate Changeaction is delete.

Change GetRuleViolations to accept the ChangeAction parameter and add a parameterless version that calls it with ChangeAction.None (or Update or Insert, as appropriate). Then move your check in there as you want.
public IEnumerable<RuleViolation> GetRuleViolations( ChangeAction action )
{
if (action == ChangeAction.Delete) {
...
}
else {
...
}
}
public IEnumerable<RuleViolation> GetRuleViolations()
{
return GetRuleViolations( ChangeAction.None );
}

Related

How to Dispatch symfony events within entity manager transaction

I am looking for a smarter way to dispatch a symfony event within entity manager transactional, so that in case of rollback it won't complain.
Here's the sample of code:
$this->em->transactional(
function () use ($xyz, $oldXyz) {
if ($oldXyz !== null) {
$this->doRemove($oldXyz);
}
$this->em->persist($xyz);
}
);
Where:
private function doRemove(XyzInterface $oldXyz): void
{
$this->em->remove($oldXyz);
$this->em->flush();
$this->dispatcher->dispatch(new XyzEvent($oldXyz), XyzEvents::onXyzDeleted);
}
This thing will complain 'app.ERROR: Pending transaction on master connection' because this due to event dispatching cannot be rollback.
I can not move out event dispatch from doRemove, because it's used somewhere else plus it's job of doRemove to dispatch this event here, since actual removing happens here only.
Any help would be appreciated, thank you all in advance.
Just return $oldXyz to the caller (by editing the closure as follows)
function () use ($xyz, $oldXyz) {
if ($oldXyz !== null) {
$this->doRemove($oldXyz);
return $oldXyz;
}
$this->em->persist($xyz);
return null;
}
Then check for returned value and dispatch
$oldXyz = $this->em->transactional(...);
if ($oldXyz instanceof <FQCNForOldXyz>) {
$this->dispatcher->dispatch(new XyzEvent($oldXyz), XyzEvents::onXyzDeleted);
}
Didn't tried directly, but I'm pretty confident it works.

Async task ASP.net HttpContext.Current.Items is empty - How do handle this?

We are running a very large web application in asp.net MVC .NET 4.0. Recently we had an audit done and the performance team says that there were a lot of null reference exceptions.
So I started investigating it from the dumps and event viewer.
My understanding was as follows:
We are using Asyn Tasks in our controllers. We rely on HttpContext.Current.Items hashtable to store a lot of Application level values.
Task<Articles>.Factory.StartNew(() =>
{
System.Web.HttpContext.Current = ControllerContext.HttpContext.ApplicationInstance.Context;
var service = new ArticlesService(page);
return service.GetArticles();
}).ContinueWith(t => SetResult(t, "articles"));
So we are copying the context object onto the new thread that is spawned from Task factory. This context.Items is used again in the thread wherever necessary.
Say for ex:
public class SomeClass
{
internal static int StreamID
{
get
{
if (HttpContext.Current != null)
{
return (int)HttpContext.Current.Items["StreamID"];
}
else
{
return DEFAULT_STREAM_ID;
}
}
}
This runs fine as long as number of parallel requests are optimal. My questions are as follows:
1. When the load is more and there are too many parallel requests, I notice that HttpContext.Current.Items is empty. I am not able to figure out a reason for this and this causes all the null reference exceptions.
2. How do we make sure it is not null ? Any workaround if present ?
NOTE: I read through in StackOverflow and people have questions like HttpContext.Current is null - but in my case it is not null and its empty. I was reading one more article where the author says that sometimes request object is terminated and it may cause problems since dispose is already called on objects. I am doing a copy of Context object - its just a shallow copy and not a deep copy.
Your problem is that a instance members of the HttpContext are not thread safe:
Any public static (Shared in Visual Basic) members of this type are
thread safe. Any instance members are not guaranteed to be thread
safe.
When accessing it the way you are doing (multiple threads) you need to do your own synchronization.
static object locker = new object();
get
{
lock (locker)
{
if (HttpContext.Current != null)
{
return (int)HttpContext.Current.Items["StreamID"];
}
else
{
return DEFAULT_STREAM_ID;
}
}
}
MSDN: system.web.httpcontext
Maybe I'm misreading this, but I'm getting the impression that you're only trying to prevent the null reference error.
public class SomeClass
{
internal static int StreamID
{
get
{
int returnValue;
if (HttpContext.Current != null)
{
if(HttpContext.Current.Items["StreamID"] != null)
{
returnValue = (int)HttpContext.Current.Items["StreamID"];
}
else
{
returnValue = DEFAULT_STREAM_ID;
}
}
else
{
returnValue = DEFAULT_STREAM_ID;
}
return returnValue;
}
}
}

event expected not to raise is raising

I have an event and a raising method as below :
public class Events {
public event EventHandler<CustomEventArgs> Succeed;
public virtual void OnSucceed(object sender, params object[] data)
{
CustomEventArgs args = new CustomEventArgs(data);
EventHandler<CustomEventArgs> _succeed = Succeed;
if (_succeed != null)
{
_succeed(sender, args);
}
}}
I have created a unit test for the OnSucceed method (using FluentAssertions ):
[Test]
public void SucceedShouldNotBeRaisedTest()
{
Events events = new Events();
events.MonitorEvents();
events.OnSucceed(this,"somedata");
events.ShouldNotRaise("Succeed");
}
as there is no subscriber to the event then I expect it not to raise Succeed event
but the test fails as Succeed event is raised . what's wrong with this ?!
When you call events.MonitorEvents();, FluentAssertions automatically subscribe to the public events to detect when an event has been raised.
Your test is failing because your condition will always evaluate to true: if (_succeed != null). When testing, the event will always be different from null
Now I would like to recommend you to following approach proposed by Jon Skeet:
public event EventHandler<CustomEventArgs> Succeed = delegate { } ;
With the above event declaration, your event will never be null (an event cannot be assigned from outside of its class)
Note: You can assign the delegate behind the event to null inside its class like this:
this.Succeed = null;
The above statement is assigning the delegate behind the event to null, not the event itself. Usually you won't need to do something like this, but in case you do, you would have to re-initialize the event like this:
this.Succeed = null;
this.Succeed = delegate { };
If you follow these suggestions, your event will never be null and you won't need to call the if(this.MyEvent != null) condition in order to raise your events anymore. (Note that this condition was totally technical and it's not related to the domain itself.)
Now that you have removed that technical condition you can actually focus in the domain rules to decide when to raise the event.
The last step would be to remove: if (_succeed != null) and add a condition indicating if the event should or should not be raised based on your current domain
if(shouldRaiseEvent)
{
EventHandler<CustomEventArgs> _succeed = Succeed;
_succeed(...);
}
For your tests, you just need to configure your Subject Under Test with the required conditions in order to raise or not raise your events.
Full sample:
public class Events {
public event EventHandler<CustomEventArgs> Succeed = delegate { };
public virtual void OnSucceed(object sender, params object[] data)
{
if (/*[optional] here your domain condition that will indicate if the event should be raised*/)
{
// this is a best practice to deal with multi-threading situations
var _succeed = this.Succeed;
var args = new CustomEventArgs(data);
_succeed(sender, args);
}
}
}

ViewModelBase.IsInDesignModeStatic Property

I am sure this is a MVVM Light newbie error but I need to ask. I am creating an WPF4 application using the MVVM Light framework and Ninject for DI. In the ViewModelLocator contructor I pass in the ViewModelBase.IsInDesignModeStatic value so I know to create DI with DesignTime data or RunTime data.
I thought that when you opened the MainWindow.xml in the designer ( VS2010 or Blend ) that the property would be True and the constructor would execute and break in debug if I had a breakpoint set. The application runs fine and debugs when ran correctly but I never get designtime data because the property is always false. Also does not seem that the constructor is executing when opened in designer. I have watched Laurent's videos multiple times and I know this does work. Can someone please tell me what they think I must be doing wrong.
Orgbrat
I'm late, but try this when troubleshooting this kind of problem.
You'll need a simple Property to test: Create a "Foo" property (string) in the ViewModel and bind it to the XAML (use a TextBlock for example).
In the ViewModel
In the "Get", return an hard coded string (ex: "Step 1". This will validate the "bindings" are valid.
Remove the "Get" hard code, and in the constructor, put a this.Foo = "Step 2" in the first line, this will validate that the constructor is called
Put a third set where the call is "callbacked", this will check that the GetData is being returned
in the "else" of the if (error != null), put the fourth set, and so on...
Example: Here's my MainViewModel constructor.
public MainViewModel(IDataService dataService)
{
this.Foo = "Step 2";
_dataService = dataService;
_dataService.GetData(
(item, error) =>
{
this.Foo = "Step 3";
if (error != null)
{
// Report error here
return;
}
else
{
this.Foo = "Step 4";
}
});
}
My last bug was that I had put the assignment of the data coming back from the GetData in the "if (error != null){...}" ! So it was never called.
Since then, I rewrite the constructor like this:
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
_dataService.GetData(
(item, error) =>
{
if (error == null)
{
// Normal code here
return;
}
else
{
// Report error here
return;
}
});
}

Propagating QueryString parameter in RedirectToAction calls

I want to make sure that a particular parameter in the QueryString, in my case the request_id is propagated to the redirected action.
Say for example, I have an Action First,
[HttpPost]
public ActionResult First()
{
////////////////////
// Lots of code ...
////////////////////
return RedirectToAction("Second");
}
Now say, the First postback had a parameter in the QueryString, which I would like to pass to the Second action. One way to do it would be to pass the value in the RedirectToAction call itself,
string requestId = Request.QueryString[REQUEST_ID_KEY];
return RedirectToAction("Second", new { REQUEST_ID_KEY = requestId });
But I have to do this in a series of Actions and I am unwilling to incorporate request id propagation logic inside the action. It would be better if I could incorporate this inside an ActionFilter, but I cant figure out how to add parameters to the QueryString from an ActionFilter. Any ideas?
public class PreserveQueryStringAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var redirectResult = filterContext.Result as RedirectToRouteResult;
if (redirectResult == null)
{
return;
}
var query = filterContext.HttpContext.Request.QueryString;
// Remark: here you could decide if you want to propagate all
// query string values or a particular one. In my example I am
// propagating all query string values that are not already part of
// the route values
foreach (string key in query.Keys)
{
if (!redirectResult.RouteValues.ContainsKey(key))
{
redirectResult.RouteValues.Add(key, query[key]);
}
}
}
}
and then:
[HttpPost]
[PreserveQueryString]
public ActionResult First()
{
////////////////////
// Lots of code ...
////////////////////
return RedirectToAction("Second");
}
If you need it in subsequent action than please add it that param in Session or TempData (But need to re-assign in each action) so you dont need to pass it as a querystring in each action. In case of session, once you done with all actions than remove that key from the Session.
Here is a blogpost I wrote on how to fluently add querystring parameters in the action

Resources