Cancel long running requests in ASP .NET MVC 2 - session

in my ASP .NET MVC2 application, there are two controller methods:
public class MyController : Controller{
public ActionResult Optimization(...){
//long running optimization
//this method writes to the Session
}
public void StopOptimization(){
//user wants to stop the optimization
//no access to Session needed
}
}
So in order to stop my long running optimization, the "Stop"-Method should be let through by ASP .NET MVC while the "Optimization"-Method is running.
I know that requests can be processed in parallel only if the SessionSate is at least set to "ReadOnly" for the whole controller class. I already followed the steps in this blog post.
However, this implies that data cannot be written to the Session anymore, which is required by the Optimization-Method.
For this reason, I have decided to remove the "Stop"-Method from this Controller and put it in an extra Controller, for which I set the SessionState to "ReadOnly":
...
using Microsoft.Web.Mvc;
...
[ControllerSessionState(ControllerSessionState.ReadOnly)]
public class StopController: Controller
{
public void Stop()
{
//Stop long running optimization
}
}
However, the Stop-Request is still only processed after the Optimization in the other controller is completed.
Additionally I tried to implement a custom controller factory that allows to define the session state for each ActionMethod separately - this is described here. This has not worked for me as I do not use ASP .NET MVC 3, but only ASP .NET MVC 2 in conjunction with the MVC Futures Library.
Does anyone have an idea how I can implement a Stop-Method that allows the user to stop my long running method from client-side?

Related

Dependecy Injection in MVC 5 with ajax calls

So I recently found out about dependency injection and read a lot about the pros and cons and I was curious if it would be "good" using it in my app as i couldn't find an example of something like I have at the moment.
My app at the moment is 100% based on Ajax requests my typical controller looks like this:
public JsonResult Controller()
{
getStuff from the model
return JSON(info from controller)
}
Is DI a good choice for this situation? Or is are the benefits (if any) slim to none?
PS: I don't know if this matter much, but I only use 1 database.
If you have a large application with multiple dependencies then DI is a good choice. Even if your app is relatively small and only requires the database connection to be injected, this could be a good starting point for you into DI.
For the code example you provided, assuming you're using controller injection and you require a database connection, you'll end up with something similar to:
public class MyController
{
IDatabase database;
public MyController(IDatabase database)
{
this.database = database;
}
public JSONResult MyControllerMethod()
{
var myData = database.GetData();
return JSON(myData)
}
}
Then you would need to configure your DI container so it knows which concrete classes to inject for which interfaces - depending on the framework you use, this will differ slightly.
Given you don't have a lot of experience with it, keep in mind there will be a bit of a learning curve while you get your head around it. I'm assuming you're using WebAPI for your AJAX calls in which case this page is an excellent resource to get you started - http://www.asp.net/web-api/overview/advanced/dependency-injection

Umbraco ApiController actions wont map to http-verb

I have been working some with the Web API before.. and as far as I can remember..
The actions in (at least the new version) is called Get,Post,Delete,Put etc...
and these actions are triggered depending of the http-verb in the request..
So for instance you might have an ApiController called UserApiController..
and if you do a request to /api/user with the POST http-verb.. then the Post-action in that controller will be triggered/executed..
However....
it seems like Im having some trouble with this using the UmbracoApiController... for some reason it wont execute post or get or any other action mapped to the http-verb..
Any ideas?.. is there any other way to sort of force a method to be executed depending on the http-verb?
My current code is:
public class MyController : UmbracoApiController
{
[HttpPost]
public bool Post()
{
return true;
}
}
I have placed a breakpoint with in the action..
The reason they won't be accepted is you're using the wrong attribute - HttpPost is part of the System.Web.Mvc namespace, whereas Web API is part of the System.Web.Http namespace.
You have to use AcceptVerbs("POST") instead.

Passing User Info to MVC Controller

I am looking at various methods to implement Authentication in my MVC3 app. I would like to use my own code to do the authentication – something similar to Is it possible to create a Logon System with ASP.NET MVC but not use the MembershipProvider? (I know that there are other methods.) I would like to know once I authenticate a user using one of these methods, how do I get the user information to the Controller constructor. (By user information I mean username or userID).
One of the options I considered is putting that info into the Session. This works, but it is difficult to test since I get the Session out of the Context which does not exist during the test.
I would appreciate any ideas for how to pass user info to the controller constructor.
No. Do not use Session for authentication. It's less secure, and unstable (sessions can be destroyed at will by the server).
In MVC, you don't need to use membership at all, but.. and I will make a point of emphasizing the but... Doing authentication correctly is not a trivial task. It's very very very easy to get it wrong and not even realize it. Even if you know what you're doing. It's something that should be heavily analyzed, tested, verified, and re-analyzed.
I would suggest, if you don't want to extend this effort, you should probably just use the default providers (there are several you can choose from).
But in any event, if you are determined to do it yourself, all you need is some way to verify the user. MVC does not integrate with the membership provider like WebForms does. It uses it for convenience. If you look in the default AccountController that is generated for you if you create an Internet project, all it does is call Membership.VerifyUser().
The truly important thing is the Authentication cookie system, which MS provides in the form of the FormsAuthentication class. I would VERY strongly recommend using this for the cookie management, unless you REALLY REALLY REALLY know what you are doing.
Just look in the AccountController, and it should be very obvious how this works. FormsAuthentication is the part that integrates into the app and tells asp.net that the user has already been authenticated. It uses a secure, encrypted cookie, and it's well designed (it even allows you to store your own additional data in an encrypted format).
Forms Authentication is a set of classes that work together to provide a transparent authentication mechanism, and is integrated into MVC and Asp.net WebForms. They are basically an implementation of the IPrincipal and IIdentity system, which is integral to asp.net (if you type User.IsAuthenticated this uses the IPrincipal interface).
In my original post I was looking at passing User Info to the Controller constructor. I did not want the Controller to depend on HttpContext, because this would make it difficult to test.
While I thank Mystere Man for his solution, I hope the following alternate solution would help someone. I have a small project (about a dozen controllers) so it is not too bad.
I basically created my custom ControllerFactory inheriting from DefaultControllerFactory:
public class MyCustomControllerFactory : DefaultControllerFactory
{
public MyCustomControllerFactory ()
{
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return null;
}
else
{
//Example of User Info - Customer ID
string customerIDStr = requestContext.HttpContext.Session["CustomerID"].ToString();
int customerID = Int32.Parse(customerIDStr);
//Now we create each of the Controllers manually
if (controllerType == typeof(MyFirstController))
{
return new MyFirstController(customerID);
}
else if (controllerType == typeof(MySecondController))
{
return new MySecondController(customerID);
}
//Add/Create Controllers similarly
else //For all normal Controllers i.e. with no Arguments
{
return base.GetControllerInstance(requestContext, controllerType);
}
}
}
}
I then set the ControllerFactory in the Global.asax.cs Application_Start() method.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new MyCustomControllerFactory ());
}
P.S. I looked into using DI Containers like Ninject, but I think they were too complicated for my current project. I would look at them in a few months when it really makes sense to use them.

MVC Autofac ExtensibleActionInvoker stops me using interface parameters

I have a problem with the Autofac ExtensibleActionInvoker interacting with the MVC ModelBinder when using interfaces for parameters. The background is as follows:
I am building a MVC application and I am using Autofac MVC3's ExtensibleActionInvoker to inject my services as parameters to my actions, e.g.
public ActionResult Test( IMyService service)
{
//A new instance of service is created by Autofac ExtensibleActionInvoker
return View();
}
This works really well and makes for a really clean design (see Alex Meyer-Gleaves post for more information on this approach). I want to use this method as I am producing a code generator to create actions, views, services and DTOs and a per-action service approach makes this easier.
However I also want to use interfaces for the parameters in action classed which receive input from an HttpPost action. This is because I use DI to create classes outside each layer. If I change the DefaultModelBinder to use DI to create the class (see page 595 of Steve Sanderson's book on MVC3 on how to do this) this this works fine, e.g.
[HttpPost]
public ActionResult Test(ITestClass dataComingFromView)
{
//model binder creates the class via DI and then binds it to the data from the post
return View();
}
However in the above simple example above I get a conflict with the ExtensibleActionInvoker enabled, i.e.
Without ExtensibleActionInvoker enabled the method above works fine, i.e. the extended
DefaultModelBinder uses DI to create the TestClass class and modelbinder binds
input from the view to the fields in the class.
With ExtensibleActionInvoker enabled it does not work, i.e. I get an empty TestClass class with no binding. I assume the ExtensibleActionInvoker takes precedence over the model binder and just creates an empty TestClass class.
(Just for completeness I should say that if I just use MVC "out of the box", i.e. no new DefaultModelBinder and no ExtensibleActionInvoker enabled, then it says you cannot use an interface as an Action method parameter.)
My question for anyone with better Autofac knowledge than me is: can I change the Autofac ExtensibleActionInvoker to select what it binds to? All my injected service classed start with IService so I could filter on that. I know you can do that in Autofac elsewhere but couldn't see anything to do that with ExtensibleActionInvoker, but maybe I missed it.
Any help would be appreciated.
Jon Smith - Selective Analytics
You are correct that the problem is caused by the ExtensibleActionInvoker class. If you look at the source for it, there is a method called GetParameterValue(). See below:
protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
{
if (_injectActionMethodParameters)
return _context.ResolveOptional(parameterDescriptor.ParameterType) ?? base.GetParameterValue(controllerContext, parameterDescriptor);
return base.GetParameterValue(controllerContext, parameterDescriptor);
}
This method overrides the method that eventually uses the MVC framework's model binder infrastructure. What this means, is that the ActionInvoker tries to resolve the parameter using AutoFac first, and if it fails, falls back to the default functionality. Based on the results you are getting, it seems that your AutoFac configuration must be setup to provide a default resolution of ITestClass.
In order to register a custom ModelBinder with AutoFac you have a couple options. You can decorate the view model with a ModelBinderTypeAttribute or you can do it in your configuration with the custom extension methods found in RegistrationExtensions.
One article I found looks like it provides an easy solution to a similar issue (see the end), but I have not tested this personally.
Having now worked on this problem I found a simple answer. My problem was due to me not really understanding how the MVC Model Binding worked.
If you look at my orginal problem I had created a DefaultModelBinder to allow me to use interfaces as my model parameters (see original question at the top). This was added after me including the Autofac's ExtensibleActionInvoker to bind my IService types. The problem was that the two DI approaches clashed.
The answer was that the DefaultModelBinder was sufficient to bind both my data classes and the Service definitions, so I do not need Autofac's ExtensibleActionInvoker. For completeness I have included the DefaultModelBinder code in case it is useful to anyone else.
public class DiModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
return modelType.IsInterface
? DependencyResolver.Current.GetService(modelType)
: base.CreateModel(controllerContext, bindingContext, modelType);
}
}
Note that I only call the DependencyResolver if the modeltype is an interface as I don't pass abstract classes between layers. Any alternative is to always call the DependencyResolver and then call the base.CreateModel if the DI does not resolve the type. I didn't do this because calling the DependencyResolver is slightly expensive so I only call it when I know I need it.

Authorisation exceptions

I've tagged my controller with an authority annotation but would like to exempt one of the methods... can that be done? how?
[Authorize(Roles="Admin")]
public class ProductController : Controller
{
[DEAUTHORIZE]
public ActionResult Start(int it)
{ ... }
In MVC 4 was introduced AllowAnonymousAttribute which tells action invoker to skip AuthorizeAttribute.
[AllowAnonymous]
No, this can't be done. The standard way to achieve this is to simply move the Start action out in a separate controller. Another possibility consists into building a custom IFilterProvider which will apply the authorization attribute conditionally instead of baking it manually into the ProductController. For example NInject uses this and provides a pretty fluent syntax into configuring action filters. You can conditionally apply them based on the current context.

Resources