Wizard in asp.NET MVC3 using a static object - asp.net-mvc

I'm trying to make a wizard in MVC3 using Entity Framework. It needs to keep the state of an object (an article in this case) across a couple of steps.
I have a static variable in my controller that instantiates a new Article. In the different Actions I use TryUpdateModel to map the form to the static variable. The problem is, it seems that TryUpdateModel() updates the database as well. I need TryUpdateModel to do the automatic mapping, and update the static _article variable, but I don't want it to persist to the database until the last step!
N.B: I know there are a lot of possible solutions for creating a wizard in MVC, but I'd like to know what to do to make this way work, so please no alternatives for an MVC wizard-pattern.
Thanks.
namespace website.Controllers
{
public class ArticlesController : BaseController
{
// private static variable to hold the chosen article in the wizard
private static articles _article = new articles();
/// <summary>
/// Index page shows a list of articles in a webgrid
/// </summary>
/// <returns></returns>
public ActionResult Index()
{
List<articles> _articles = Data.getArticles();
return View(_articles);
}
/// <summary>
/// First page of the article wizard
/// </summary>
/// <returns></returns>
public ActionResult BasicDetails(string id, string nextButton)
{
// back or next doesn't matter - store form values
if (_article != null) TryUpdateModel(_article);
if (nextButton != null)
{
return RedirectToAction("ArticleGroup");
}
else
{
_article = Data.GetArticleById(id);
return View(_article);
}
}
/// <summary>
/// Second page of the article wizard
/// </summary>
/// <returns></returns>
public ActionResult ArticleGroup(string nextButton, string backButton)
{
TryUpdateModel(_article);
if (backButton != null)
return RedirectToAction("BasicDetails");
else if (nextButton != null)
{
return RedirectToAction("Price");
}
else
{
return View(_article);
}
}
/// <summary>
/// Third page of the article wizard
/// </summary>
/// <returns></returns>
public ActionResult Price(string nextButton, string backButton)
{
TryUpdateModel(_article);
if (backButton != null)
{
return RedirectToAction("ArticleGroup");
}
else if (nextButton != null)
return RedirectToAction("LinkedClubs");
else
{
return View(_article);
}
}
/// <summary>
/// Last page of the article wizard
/// </summary>
/// <returns></returns>
public ActionResult LinkedClubs(string backButton)
{
if (backButton != null)
return RedirectToAction("Price");
else
return View(_article);
}
}
}

Rather than using a static variable to hold your state information (that is a critical error btw) you should pass a state bag holding the information that you need in between pages.

Usually data entities (entities mapped to database) and viewmodel entities (entities with that user works) used separately. When user posted data after some step - you make TryUpdateModel() to session object (specific for user, not for all application as static variable).
At last step you call business logic method UpdateModel(viewmodel), that update all columns by id of viewmodel, using all filled properties.

Related

MVCSiteMap Node Requring Multiple Roles

I've set up my menu using MVCSiteMap and I have this node:
<mvcSiteMapNode title="Courses Form" controller="Booking" action="Course" roles="CORLIC, VIEWCOBO"/>
I'm trying to enforce that this node must have roles "CORLIC" AND "VIEWCOBO" for it to be visible but of course this means that it will be displayed if the user has either of the above.
Is this possible?
Thanks.
The roles attribute is for interoperability with ASP.NET and should not be used in an MVC-only application.
For MVC, if you are already defining the AuthorizeAttribute on your controller actions, MvcSiteMapProvider will automatically pick them up and hide the matching nodes accordingly if security trimming is enabled.
[Authorize]
public ActionResult Course()
{
return View();
}
[Authorize]
[HttpPost]
public ActionResult Course(CourseModel model)
{
if (ModelState.IsValid)
{
// Implementation omitted
}
// If we got this far, something failed, redisplay form
return View(model);
}
The default AuthorizeAttribute accepts roles, but it works in the same way as the roles attribute - that is, any role that the user is in will cause it to succeed.
However, you could inherit AuthorizeAttribute yourself and override the IsAuthorized method to change the logic as needed.
public class SpecialAuthorizeAttribute : AuthorizeAttribute
{
private string _requiredRoles;
private string[] _requiredRolesSplit = new string[0];
/// <summary>
/// Gets or sets the required roles. The user must be a member of all roles for it to succeed.
/// </summary>
/// <value>
/// The roles string.
/// </value>
/// <remarks>Multiple role names can be specified using the comma character as a separator.</remarks>
public string RequiredRoles
{
get { return _requiredRoles ?? String.Empty; }
set
{
_requiredRoles = value;
_requiredRolesSplit = SplitString(value);
}
}
/// <summary>
/// Determines whether access for this particular request is authorized. This method uses the user <see cref="IPrincipal"/>
/// returned via <see cref="HttpRequestContext.Principal"/>. Authorization is denied if the user is not authenticated,
/// the user is not in the authorized group of <see cref="Users"/> (if defined), or if the user is not in any of the authorized
/// <see cref="Roles"/> (if defined).
/// </summary>
/// <param name="actionContext">The context.</param>
/// <returns><c>true</c> if access is authorized; otherwise <c>false</c>.</returns>
protected override bool IsAuthorized(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException("actionContext");
}
IPrincipal user = actionContext.ControllerContext.RequestContext.Principal;
if (user == null || user.Identity == null || !user.Identity.IsAuthenticated)
{
return false;
}
// Ensure all of the roles in RequiredRoles are present.
if (_requiredRolesSplit.Length > 0 && !_requiredRolesSplit.All(user.IsInRole))
{
return false;
}
// Call the base class to check the users and roles there.
return base.IsAuthorized(actionContext);
}
/// <summary>
/// Splits the string on commas and removes any leading/trailing whitespace from each result item.
/// </summary>
/// <param name="original">The input string.</param>
/// <returns>An array of strings parsed from the input <paramref name="original"/> string.</returns>
internal static string[] SplitString(string original)
{
if (String.IsNullOrEmpty(original))
{
return new string[0];
}
var split = from piece in original.Split(',')
let trimmed = piece.Trim()
where !String.IsNullOrEmpty(trimmed)
select trimmed;
return split.ToArray();
}
}
Then you can specify which roles are required by using the new property.
[SpecialAuthorize(RequiredRoles = "CORLIC, VIEWCOBO")]
public ActionResult Course()
{
return View();
}
[SpecialAuthorize(RequiredRoles = "CORLIC, VIEWCOBO")]
[HttpPost]
public ActionResult Course(CourseModel model)
{
if (ModelState.IsValid)
{
// Implementation omitted
}
// If we got this far, something failed, redisplay form
return View(model);
}
Another possible option is to use FluentSecurity as shown here. For FluentSecurity v2.0 to work with MvcSiteMapProvider, you need to copy the HandleSecurityAttribute code into your project and change it to inherit from AuthorizeAttribute instead of Attribute, then use it as specified in the FluentSecurity documentation.

windsor nHibernate ISession

I have a MVC5 application and set my hibernate stuff up like that:
public class PersistenceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
//Nhibernate session factory
Component.For<ISessionFactory>().UsingFactoryMethod(CreateNhSessionFactory).LifeStyle.Singleton,
Component.For<ISession>().UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession()).LifestylePerWebRequest(),
//All repoistories
Classes.FromAssembly(Assembly.GetAssembly(typeof(HdtRepository))).InSameNamespaceAs<HdtRepository>().WithService.DefaultInterfaces().LifestyleTransient()
);
}
and my base repository looks like that:
public abstract class RepositoryBase<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey> where TEntity : Entity<TPrimaryKey>
{
/// <summary>
/// Gets the NHibernate session object to perform database operations.
/// </summary>
public ISession Session { get; set; }
/// <summary>
/// Used to get a IQueryable that is used to retrive object from entire table.
/// </summary>
/// <returns>IQueryable to be used to select entities from database</returns>
public IQueryable<TEntity> GetAll()
{
return Session.Query<TEntity>();
}
/// <summary>
/// Gets an entity.
/// </summary>
/// <param name="key">Primary key of the entity to get</param>
/// <returns>Entity</returns>
public TEntity Get(TPrimaryKey key)
{
return Session.Get<TEntity>(key);
}
/// <summary>
/// Inserts a new entity.
/// </summary>
/// <param name="entity">Entity</param>
public void Insert(TEntity entity)
{
Session.Save(entity);
}
/// <summary>
/// Updates an existing entity.
/// </summary>
/// <param name="entity">Entity</param>
public void Update(TEntity entity)
{
Session.Update(entity);
}
/// <summary>
/// Deletes an entity.
/// </summary>
/// <param name="id">Id of the entity</param>
public void Delete(TPrimaryKey id)
{
Session.Delete(Session.Load<TEntity>(id));
}
}
Everything works corret when I Insert a entity.
Update is onyl working when I add a Session.Flush() to my Update method.
This is the mehtod which is called from Ajax and performs insert or update.
[Authorize]
[ValidateInput(false)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public JsonNetResult CreateOrUpdateTimeRecord(TimeRecord tr)
{
TimeRecord trLocal;
if (tr.Id == -1 || tr.Id == 0)
{
trLocal = new TimeRecord();
trLocal.Description = tr.Description;
trLocal.StartTime = tr.StartTime;
trLocal.EndTime = tr.EndTime;
trLocal.User = _userRepo.Get(tr.User.Id);
trLocal.Hdt = _hdtRepo.Get(tr.Hdt.Id);
_timeRepo.Insert(trLocal);
}
else
{
trLocal = _timeRepo.Get(tr.Id);
trLocal.Description = tr.Description;
trLocal.StartTime = tr.StartTime;
trLocal.EndTime = tr.EndTime;
_timeRepo.Update(trLocal);
}
return new JsonNetResult() { Data = trLocal};
}
I dont understand why this works for insert and not for Update.
Do I have to care about transaction and opening/closing Sessions?
I thought that "LifestylePerWebRequest" would do that for me.
Cheers,
Stefan
:edit: (my initial answer was partially wrong)
You implementation should actually work fine (just tested it).
Though I can reproduce the behavior that updates are not flushed although the session object gets disposed correctly
The LifestylePerWebRequest actually takes care of that just fine, it will dispose the session whenever the request ends. Therefore you had to add the request handle to the web.config etc... So the windsor stuff is perfectly aware of the fact that ISession is disposable and that it has to dispose it...
This is because of the the FlushMode of the session.
The default mode is Auto, which might not be really what you want because you cannot rely on the changes getting stored (especially with update calls).
You can either change the FlushMode of the created session object, or, and this is what I recommend, use transactions.
Lets look at the following example:
var session = container.Resolve<ISession>();
var obj = new Paper()
{
Author = "Author",
Description = "Description",
};
session.Save(obj);
obj.Author = "Author2";
session.Update(obj);
In this case, the update will never be flushed/stored in the database. This is the behavior you currently have I guess.
Now lets add a transaction around it:
var session = container.Resolve<ISession>();
using (var transaction = session.BeginTransaction())
{
var obj = new Paper()
{
Author = "Author",
Description = "Description",
};
session.Save(obj);
obj.Author = "Author2";
session.Update(obj);
transaction.Commit();
}
Now the changes will be saved for sure.

Can I define custom attributes for proxy type in Castle Windsor

I have a class that I proxy it with Castle Dynamic Proxy. I want to add some custom Attributes to proxy methods (which is not defined in proxied class). Is this possible.
I want this because I want to generate ASP.NET Web API layer for my application's Service Layer. I proxied services (with inheriting from ApiController and additional IMyService interfaces), it works great but I want to add WebAPI specific attributes to this newly created Dynamic class, thus Web API framework can read them.
EDIT:
I want to explain detailed if someone want to know what I want actually.
public interface IMyService
{
IEnumerable<MyEntity> GetAll();
}
public class MyServiceImpl : IMyService
{
public IEnumerable<MyEntity> GetAll()
{
return new List<MyEntity>(); //TODO: Get from database!
}
}
public class MyServiceApiController : ApiController,IMyService
{
private readonly IMyService _myService;
public MyServiceApiController(IMyService myService)
{
_myService = myService;
}
public IEnumerable<MyEntity> GetAll()
{
return _myService.GetAll();
}
}
Think that I have a IMyService which is implemented by MyServiceImpl. And I want to make a Api controller to be able to use this service from web.
But as you see, api controller is just a proxy for real service. So, why I should write it? I can dynamically create it using castle windsor.
This is my idea and almost done it in my new project (https://github.com/hikalkan/aspnetboilerplate). But what if I need to add some attribute (such as Authorize) to GetAll method of the api controller. I cant directly add since there is no such a class, it's castle dynamic proxy.
So, beside this problem. I want to know if it's possible to add a attribute to a method of a synamic proxy class.
See again that project
https://github.com/aspnetboilerplate/aspnetboilerplate/issues/55
I also want to know how, so that I can define RoutePrefix on IService and Route on Action.
Fortunately, I finally know how to define custom attributes for proxy.
public class CustomProxyFactory : DefaultProxyFactory
{
#region Overrides of DefaultProxyFactory
protected override void CustomizeOptions(ProxyGenerationOptions options, IKernel kernel, ComponentModel model, object[] arguments)
{
var attributeBuilder = new CustomAttributeBuilder(typeof(DescriptionAttribute).GetConstructor(new[] { typeof(string) }), new object[] { "CustomizeOptions" });
options.AdditionalAttributes.Add(attributeBuilder);
}
#endregion
}
/// <summary>
/// 用户信息服务
/// </summary>
[Description("IUserInfoService")]
public interface IUserInfoService
{
/// <summary>
/// 获取用户信息
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[Description("IUserInfoService.GetUserInfo")]
UserInfo GetUserInfo([Description("IUserInfoService.GetUserInfo name")] string name);
}
/// <summary>
/// 用户信息服务
/// </summary>
[Description("UserInfoService")]
public class UserInfoService : IUserInfoService
{
/// <summary>
/// 获取用户信息
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[Description("UserInfoService.GetUserInfo")]
public virtual UserInfo GetUserInfo([Description("UserInfoService.GetUserInfo name")] string name)
{
return new UserInfo { Name = name };
}
}
using DescriptionAttribute = System.ComponentModel.DescriptionAttribute;
[TestFixture]
public class AttributeTests
{
/// <summary>
/// Reference to the Castle Windsor Container.
/// </summary>
public IWindsorContainer IocContainer { get; private set; }
[SetUp]
public void Initialize()
{
IocContainer = new WindsorContainer();
IocContainer.Kernel.ProxyFactory = new CustomProxyFactory();
IocContainer.Register(
Component.For<UserInfoService>()
.Proxy
.AdditionalInterfaces(typeof(IUserInfoService))
.LifestyleTransient()
);
}
/// <summary>
///
/// </summary>
[Test]
public void GetAttributeTest()
{
var userInfoService = IocContainer.Resolve<UserInfoService>();
Assert.IsNotNull(userInfoService);
var type = userInfoService.GetType();
Assert.IsTrue(type != typeof(UserInfoService));
var attribute = type.GetCustomAttribute<DescriptionAttribute>();
Assert.IsTrue(attribute != null);
Trace.WriteLine(attribute.Description);
var method = type.GetMethod("GetUserInfo");
attribute = method.GetCustomAttribute<DescriptionAttribute>();
Assert.IsTrue(attribute != null);
Trace.WriteLine(attribute.Description);
var parameter = method.GetParameters().First();
attribute = parameter.GetCustomAttribute<DescriptionAttribute>();
Assert.IsTrue(attribute != null);
Trace.WriteLine(attribute.Description);
}
}
#hikalkan I faced the same problem and I was looking for a solution as well. The best I could encounter was
How to add an attribute to a property at runtime
Proxy the controller (in my case a dynamic controller) with a new wrapper that set those attributes in the class itself and its methods..

CustomTypeDescriptor with MVC Validation - How to get property value with property.GetValue(component)?

I've created custom TypeDescriptionProvider for one of my MVC models. I use it for dynamic assignment of ValidationAttribute.
I use value of one property to decide what attributes to add to other properties. In web service, where I use DataAnnotationsValidationRunner, validation works fine.
Source of runner: here
internal static class DataAnnotationsValidationRunner
{
public static IEnumerable<ErrorInfo> GetErrors(object instance)
{
return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>()
from attribute in prop.Attributes.OfType<ValidationAttribute>()
where !attribute.IsValid(prop.GetValue(instance))
select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);
}
}
To get property value I use following code (in MyCustomTypeDescriptor)
public override PropertyDescriptorCollection GetProperties()
{
var originalProperties = base.GetProperties();
var newProperties = new List<PropertyDescriptor>();
var myProperty = originalProperties.Find("CountryCodeID", false)
var myId = (int)countryProperty.GetValue(base.GetPropertyOwner(myProperty));
foreach (PropertyDescriptor pd in originalProperties)
{
AttributeCollection runtimeAttributes = pd.Attributes;
// add new attributes based on myId value
....
}
return new PropertyDescriptorCollection(newProperties.ToArray());
}
When using this model with this descriptor in MVC View, I get following exception:
Value cannot be null. Parameter name: primary Description: An
unhandled exception occurred during the execution of the current web
request. Please review the stack trace for more information about the
error and where it originated in the code.
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: primary
What is the correct way of getting value of property within TypeDescriptor? I use this descriptor through provider on model type, not instance (e.g. global.asax).
EDIT: I've found workaround. In GetTypeDescriptor method of MyTypeDescriptorProvider I use instance parameter and pass it to consctructor of MyCustomTypeDescriptor. However, MVC validation doesn't wok. I though it uses these dynamic data automatically (similar to runner mentioned above).
EDIT 2: Using workaroud I almost always see instance null. So it is not possible to get value there and put it to consctructor of TypeDescriptor...
Thank you!
Finally I was able to use customTypeDescriptor for both - generation of HTML tags needed for client validation and validating model during binding.
First MyCustomTypeDescriptor.cs:
/// <summary>
/// CustomTypeDescriptor that provides validation in both MVC Web and WCF services.
/// </summary>
public class MyCustomTypeDescriptionProvider : TypeDescriptionProvider
{
public MyCustomTypeDescriptionProvider(TypeDescriptionProvider parent)
:base(parent)
{
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return new MyCustomTypeDescriptor(base.GetTypeDescriptor(objectType, instance));
}
}
public class MyCustomTypeDescriptor : CustomTypeDescriptor
{
public MyCustomTypeDescriptor(ICustomTypeDescriptor parent)
: base(parent)
{ }
public override PropertyDescriptorCollection GetProperties()
{
var originalProperties = base.GetProperties();
if (this.IsRequired(originalProperties))
{
var newProperties = new List<PropertyDescriptor>();
foreach (PropertyDescriptor property in originalProperties)
{
var attrs = property.Attributes;
var newAttrs = new Attribute[attrs.Count + 1];
attrs.CopyTo(newAttrs, 0);
newAttrs[attrs.Count] = new RequiredAttribute();
newProperties.Add(TypeDescriptor.CreateProperty(property.ComponentType, property, newAttrs));
}
return new PropertyDescriptorCollection(newProperties.ToArray());
}
else
{
return originalProperties;
}
}
/// <summary>
/// IsRequired just simulates more complex validation rule (dependant on another value in model)
/// </summary>
/// <param name="originalProperties"></param>
/// <returns></returns>
private bool IsRequired(PropertyDescriptorCollection originalProperties)
{
if (originalProperties == null || originalProperties.Count == 0)
{
throw new ArgumentNullException();
}
var dependantProperty = originalProperties.Find("DependantValue", false);
if (dependantProperty == null)
{
throw new InvalidOperationException();
}
var value = (int)dependantProperty.GetValue(base.GetPropertyOwner(dependantProperty));
return value > 0;
}
}
Then to bind this descriptor (per INSTANCE!) I use MyModelValidatorProvider:
/// <summary>
/// validator provider is used only for unobtrusive validation
/// </summary>
public class MyModelValidatorProvider : DataAnnotationsModelValidatorProvider
{
protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
{
var isPropertyValidation = metadata.ContainerType != null && !String.IsNullOrEmpty(metadata.PropertyName);
var model = context.Controller.ViewData.Model as TestCustomizedModel;
if (isPropertyValidation && model != null)
{
TypeDescriptor.AddProvider(new MyCustomTypeDescriptionProvider(TypeDescriptor.GetProvider(model)), model);
AttributeCollection newAttributes;
newAttributes = TypeDescriptor.GetProperties(model).Find(metadata.PropertyName, false).Attributes;
var attrArray = new Attribute[newAttributes.Count];
newAttributes.CopyTo(attrArray, 0);
attributes = attrArray;
}
return base.GetValidators(metadata, context, attributes);
}
}
This works fine, however, during ModelBinding, no ViewData is set, so ValidatorProvider doesn't hook. As a solution to this I used MyModelBinder:
/// <summary>
/// Model binder that attaches CustomTypeDescriptor and validates model.
/// </summary>
public class MyModelBinder : DefaultModelBinder
{
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
base.OnModelUpdated(controllerContext, bindingContext);
TypeDescriptor.AddProvider(new MyCustomTypeDescriptionProvider(TypeDescriptor.GetProvider(bindingContext.Model)), bindingContext.Model);
var errors = DataAnnotationRunner.GetErrors(bindingContext.Model);
if (errors != null)
{
foreach (var error in errors)
{
bindingContext.ModelState.AddModelError(error.MemberNames.FirstOrDefault() ?? string.Empty, error.ErrorMessage);
}
}
}
}
Now I can use MyCustomTypeDescriptor with DataAnnotationRunner to validate all MVC web, MVC other classes than controllers, html helpers (unobtrusive validation) and in other projects such as WCF services...
All this is fine, however it just doesn't feel right. It would be great if I was able to somehow hook MyCustomTypeDescriptor directly to MVC, however as this link claims, it doesn't seem to be possible.
How can I provide my own ICustomTypeDescriptor in ASP.NET MVC?
Any improvements that could help make this solution more elegant are welcome. Thank you.

Getting AsyncController to work with Ninject

I am trying to convert some actions within a controller to run asynchronously in an mvc project that is using ninject for dependency injection. I'm following the steps by inheriting AsyncController and changing the methods that correspond to the 'X' action to 'XAsync' and 'XCompleted' but the async action is not getting resolved. I'm confident that the issue has to do with ninject. I have tried to explicitly set ninject's Controller Action Invoker to 'AsyncControllerActionInvoker':
Bind<IActionInvoker>().To<AsyncControllerActionInvoker>().InSingletonScope();
but no luck. Has anyone managed to get Async actions working with ninject?
cheers,
Essentially the problem i was facing was that the default action invoker that is used by ninject doesnt support async actions and when you try to set the action invoker in a controller the default ninjectControllerFactory overrides it. I took the following steps to fix the problem:
1.In the injection mapping i added the following association:
Bind<IActionInvoker>().To<AsyncControllerActionInvoker>().InSingletonScope();
2.I created a custom controller factory that is basically ninject's controller factory with the only difference being that it doesn't overwrite the action invoker.
public class CustomNinjectControllerFactory : DefaultControllerFactory {
/// <summary>
/// Gets the kernel that will be used to create controllers.
/// </summary>
public IKernel Kernel { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="NinjectControllerFactory"/> class.
/// </summary>
/// <param name="kernel">The kernel that should be used to create controllers.</param>
public CustomNinjectControllerFactory(IKernel kernel) {
Kernel = kernel;
}
/// <summary>
/// Gets a controller instance of type controllerType.
/// </summary>
/// <param name="requestContext">The request context.</param>
/// <param name="controllerType">Type of controller to create.</param>
/// <returns>The controller instance.</returns>
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
if (controllerType == null) {
// let the base handle 404 errors with proper culture information
return base.GetControllerInstance(requestContext, controllerType);
}
var controller = Kernel.TryGet(controllerType) as IController;
if (controller == null)
return base.GetControllerInstance(requestContext, controllerType);
var standardController = controller as Controller;
if (standardController != null && standardController.ActionInvoker == null)
standardController.ActionInvoker = CreateActionInvoker();
return controller;
}
/// <summary>
/// Creates the action invoker.
/// </summary>
/// <returns>The action invoker.</returns>
protected virtual NinjectActionInvoker CreateActionInvoker() {
return new NinjectActionInvoker(Kernel);
}
}
3.In OnApplicationStarted() method I set the controller factory to my custom one:
ControllerBuilder.Current.SetControllerFactory(new customNinjectControllerFactory(Kernel));`
Hope this helps.
After much search i realized in addition to this, each controller needs to explicitly be set to use an Action Invoker that supports Async Actions.

Resources