ASP NET MVC Making request strange behaviour - asp.net-mvc

First of all, sorry for my bad english.
I have faced a strange problem using asp net mvc.
I have simple controller, which can execute 2 operations. The first operation is continuous and can take a several minutes. And the other is short, and executed some seconds.
Something like this:
public class TestController : Controler {
[HttpPost]
public string Func1(long id) {
// continuous operation
return new ValueGetter().Get(id)
}
[HttpPost]
public string Func2(long id) {
return "Abc";
}
}
And from the client side i call thouse methods via jqueries post:
$.post(url).sucess(...);
The problem consists in the next: while the first operation is executed, the second operation will wait, until first is finished.
I tried to use AsyncController as described there http://msdn.microsoft.com/en-us/library/ee728598.aspx, but the result is the same...
I have logged some application events in global.asax:
protected void Application_PostMapRequestHandler(object sender, EventArgs e) {
LoggerManager.Info("PostMapRequestHandler fired in global.asax");
}
protected void Application_AcquireRequestState(object sender, EventArgs e) {
LoggerManager.Info("AcquireRequestState fired in global.asax");
}
And if I for example, call the first method once, and then Immediately call the second method three times, I have the following result in the log file:
1.PostMapRequestHandler
2.AcquireRequestState
3.PostMapRequestHandler
4.PostMapRequestHandler
5.PostMapRequestHandler
... after first method is executed sucessfuly
6.AcquireRequestState
7.AcquireRequestState
8.AcquireRequestState
I use IIS 7(not express) and asp.net mvc 3
Why it happen and how I can solve it?

I found the answer to my question here:
Session less MVC Controller for MVC 2 / RC (MSDN Blogs)
I hope it will help, if someone faces a similar problem.

Related

How do I handle OperationCanceledException in ASP.NET Web APIs?

I have this simple controller, whose Get method is called with ajax to look up zipcodes via an Entity Framework repository.
[Authorize]
public class ZipCodesApiController : AppApiController
{
public ZipCode Get(string zipCode)
{
return unitOfWork.ZipCodeRepository
.Get(x => x.Zip == zipCode)
.FirstOrDefault();
}
}
In production, my logs show that System.OperationCanceledException: The operation was canceled. is thrown quite often. I think what's going on is that users are viewing an address detail page, but navigating away or closing their browser before the ajax zipcode lookup returns. I guess IIS is telling my controller that they are no longer connected, and the .NET framework throws an exception?
This seems harmless, but it also seems like a bad idea to wrap the call to ZipCodeRepository in a try and have an empty OperationCanceledException catch clause.
I've googled the error and it seems to come up quite a bit in parallel programming, which is not something I am particularly familiar with.
What is an appropriate way to handle this exception? I think it's safe to ignore, but am I wrong about that, and the Entity Framework should be alerted so that it can clean something up (my AppApiController does have a dispose method at least)?
I get the same exceptions in my web API application, however i can catch them with the Application_Error method in Global.asax.cs
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
Response.Clear();
OperationCanceledException httpException = exception as OperationCanceledException;
if (httpException != null)
{
var token = httpException.CancellationToken;
if (token.IsCancellationRequested)
{
// clear error on server
Server.ClearError();
Request.Abort();
}
}
}
I don't know if that is right.

MVC Custom error and exception handling - standard through out the project

I am new to ASP.NET MVC , Kendo UI (razor) , Jquery. I have an application that throws 3 kinds of errors
Unhanded exceptions (400, 403,500 503 etc) - throw generic exceptions
Expected exceptions/ errors (custom exceptions) - e.g. Trying to create a contact that already exist in the system - The system needs to throw "Contact_duplicated_exception" and show this to the user as "Contact was previously created. This action could not proceed".
Model state errors (UI). Errors that I add to modelstate to showup on the page using #Html.ValidationSummary(true)
What is the best standard way of handling the above throughout the application ?
I need to send these messages back to the user using Jquery Ajax [POST].
I have used the following concepts but I need to implement a standard way of dealing with the above
1. I have used ELMAH (for unhanded exceptions)
2. Application_Error(object sender, EventArgs e) in global.asax.cs
3. Custom HandleErrorArrtibute
public class HandleErrorWithAjaxFilter : HandleErrorAttribute, IExceptionFilter
Thanks!
For #1 and #3, you're looking good, IMHO. However, I think your weak-point is #2 and here is why:
If the exception is expected it should not be allowed to fall to Application_Error; because, well... it's expected, it's workflow, not an exception.
Therefore as a reaction to user input and part of workflow, it should be handled as part of #3.
So, in your shoes, I would go about in the specific instance of finding duplicates adding a validation attribute onto the potentially duplicate class like so:
[AttributeUsage(AttributeTargets.Class)]
public class UniqueContactAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
bool isValid = true;
Contact contact = value as Contact;
if(contact != null)
{
// check for your duplicate in the database and set isValid to false if you find one.
}
return isValid;
}
}
Usage for your metadata class:
[UniqueContact(ErrorMessage = "Contact was previously created. This action could not proceed.")]
public class Contact_Validation
{
}

Is it proper way of exception handling in ASP.NET MVC

I have read articles on exception handling in ASP.NET MVC. I want to make sure I am doing right by presenting it briefly. Could anyone please comment.
Catch the exceptions in controller actions, if necessary.
[HttpPost]
public ActionResult Insert()
{
try
{
}
catch
{
//ModelState.Error -> display error msg to the user.
}
}
Override the "OnException" method of controller in basecontroller and "log" the exceptions raised in step 1 and other MVC exceptions
Logged the global exceptions in application_onerror.
I would definitely recommend ELMaH instead of writing this code yourself, and also over Log4Net for your MVC apps. I personally avoid any exception handling, unless I have a specific functional response to it. In this way, I don't "eat" any of the errors that an application-wide tool such as ELMaH will handle gracefully for me.
ELMaH also has nice built-in web reporting, and there are third-party tools specifically for ELMaH that can give you statistics, e.g. the most frequent errors.
You might start with a custom error redirect...
<customErrors defaultRedirect="~/site/error" mode="RemoteOnly">
<error statusCode="404" redirect="~/site/notfound" />
</customErrors>
...to a controller that is aware you are using ELMaH...
public virtual ActionResult Error() {
System.Collections.IList errorList = new System.Collections.ArrayList();
ErrorLog.GetDefault(System.Web.HttpContext.Current).GetErrors(0, 1, errorList);
ErrorLogEntry entry = null;
if (errorList.Count > 0) {
entry = errorList[0] as Elmah.ErrorLogEntry;
}
return View(entry);
}
...backed by a view that helps the visitor get the specific error ID to you:
#model Elmah.ErrorLogEntry
#if (Context.User.Identity.IsAuthenticated) {
<p>Since you are signed in, we've noted your contact information,
and may follow up regarding this to help improve our product.</p>
} else {
<p>Since you aren't signed in, we won't contact you regarding this.</p>
}
<p>Error ID: #Model.Id</p>
I also notice this is an HttpPost in this example. If you are doing AJAX, then you'll want to handle errors for those in a unique way. Pick a standard response you can send to browsers that all of your AJAX code handles gracefully. Perhaps by displaying the ELMaH error ID in a javascript alert (as a simple example).
I also handle a few special types of AJAX errors via Global.asax:
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 302 &&
Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
HandleErrorAttribute is a nice feature, but it is well-known that there is extra work to use it in conjunction with ELMaH. How to get ELMAH to work with ASP.NET MVC [HandleError] attribute?
If you want handle exceptions in your Actions you can override "OnException" in your Controller like so:
protected override void OnException(ExceptionContext filterContext)
{
logging or user notification code here
}
You can put it in your BaseController class to prevent duplication
try and catch are for expected exceptions ie your user has entered a file name and it might not exist so you want to catch the FileNotFoundException.
For unexpected exceptions use either the Error event in the MvcApplication object e.g.
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
this.Error += MvcApplication_Error;
// Other code
}
private void MvcApplication_Error(object sender, EventArgs e)
{
Exception exception = this.Server.GetLastError();
// Do logging here.
}
}
or as Dima suggested you have controller level execption handling using
protected override void OnException(ExceptionContext filterContext)
{
// Do logging here.
}
Keep the trys and catches on code where you want to catch something expected and can handle.
"Generic" error handling just obfuscates the underlying problem, which you will have to dig for later.

User's last login with Forms Authentication

I need to record the last login info of a user into the database. So I'm thinking to put something like the code below in all of my controllers' action methods.
if (User.Identity.IsAuthenticated == true)
{
// save DateTime.Now for this user
}
However, I have a moderately huge number of controller actions. And this approach will also be difficult to manage in the long run. Is there a simpler and best way to do this?
Thanks.
[edit]
With Forms Authentication, when the logon form's "remember me" is checked, the next time the user comes back they don't go to the login page anymore. That's the reason I came up with the idea above. But I really don't like it and I will appreciate your suggestions.
The built-in MembershipUser type (which you are likely using) has a LastLoginDate and a LastActivityDate property. You should use those if possible.
If not, you can handle both "last login" and "last access" with an HttpModule:
public class LastTimeModule : IHttpModule
{
public void Init(HttpApplication context)
{
// This event is raised prior to *any* handler request ("last access")
context.PreRequestHandlerExecute += new EventHandler(OnPreRequest);
// This event is raised when a user is authenticated ("last login")
context.PostAuthenticateRequest += new EventHandler(OnPostAuthenticateRequest);
}
void OnPostAuthenticateRequest(object sender, EventArgs e)
{
// Log time here
}
public void OnPreRequest(Object source, EventArgs e)
{
// Log time here
}
}
If you're using MVC you could create a custom action filter and apply it to your controllers.

HttpContext in MVC Attributes - threading issues?

I had my NHibernate session management setup like follows:
protected MvcApplication()
{
BeginRequest += delegate
{
NHibernateSessionManager.Instance.OpenSession();
};
EndRequest += delegate
{
NHibernateSessionManager.Instance.CloseSession();
};
}
And for when I needed to save to the database, I made an ActionFilterAttribute that looked like this:
public class TransactionAttribute: ActionFilterAttribute
{
private ITransaction _currentTransaction;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
_currentTransaction = NHibernateSessionManager.Instance.CurrentSession.Transaction;
_currentTransaction.Begin();
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (_currentTransaction.IsActive)
{
if (filterContext.Exception == null)
_currentTransaction.Commit();
else
{
_currentTransaction.Rollback();
}
}
_currentTransaction.Dispose();
}
}
and then I could just add [Transaction] to my action method. This seemed to work in initial testing, but I then I tried using at HttpWebRequest to call an action method from another app multiple times and I had issues. Testing with Fiddler I setup a POST request and then fired them off in quick succession and it showed up the following:
THe red ones are various errors that I believe is to do with threading.
My NHibernateSessionManager uses the HTtpContext to store the session like this:
public ISession CurrentSession
{
get { return (ISession)HttpContext.Current.Items["current.session"]; }
set { HttpContext.Current.Items["current.session"] = value; }
}
So, to fixed it, I moved my Transaction code into my BeginRequest and EndRequest methods - and then I could fire off heaps in succession.
My question is - why did this fix it? I would have thought that I would have had something similar to this:
Begin Request - opens session
OnActionExecuting - starts transaction
action code
OnActionExecuted - commits transaction
End Request - closes session
and that this would be unique to each request, so it shouldn't interfere with one another, because there should be a different HttpContext for each request shouldn't there? Or are they shared or something??
Can someone enlighten me?
Quote from the release notes of ASP.NET MVC 3:
In previous versions of ASP.NET MVC,
action filters were created per
request except in a few cases. This
behavior was never a guaranteed
behavior but merely an implementation
detail and the contract for filters
was to consider them stateless. In
ASP.NET MVC 3, filters are cached more
aggressively. Therefore, any custom
action filters which improperly store
instance state might be broken.
This basically means that the _currentTransaction instance you have in your action filter might not be what you think it is. So be careful how/when is this property injected => it is not clear from the code you have shown.

Resources