Configuring Ninject with Asp.Net MVC & Web Api - asp.net

i have setup my project with Ninject IoC.
My project has regular Asp.Net MVC controllers and Web Api controllers. Now, Ninject works with Web Api but Ninject doesn't work with regular Asp.MVC controllers.
My regular MVC controller implementation;
public class GalleryController : BaseController
{
public GalleryController(IUow uow)
{
Uow = uow;
}
........
}
Error when using with regular controller
An error occurred when trying to create a controller of type 'Web.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor.]
However, when i try the same code with Web Api, it works
public class GalleryController : BaseApiController
{
public GalleryController(IUow uow)
{
Uow = uow;
}
......
}
my interface which holds difference repositories (the factory pattern)
public interface IUow
{
// Save pending changes to the data store.
void Commit();
//Repositoryries
IRepository<Gallery> Gallery { get; }
IMenuRepository Menus { get; }
}
NinjectDependencyScope class;
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
Contract.Assert(resolver != null);
this.resolver = resolver;
}
public void Dispose()
{
var disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.GetAll(serviceType);
}
}
NinjectDependencyResolver class;
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
Ninject configuration for Global.asax;
public class IocConfig
{
public static void RegisterIoc(HttpConfiguration config)
{
var kernel = new StandardKernel(); // Ninject IoC
//kernel.Load(Assembly.GetExecutingAssembly()); //only required for asp.net mvc (not for webapi)
// These registrations are "per instance request".
// See http://blog.bobcravens.com/2010/03/ninject-life-cycle-management-or-scoping/
kernel.Bind<RepositoryFactories>().To<RepositoryFactories>()
.InSingletonScope();
kernel.Bind<IRepositoryProvider>().To<RepositoryProvider>();
kernel.Bind<IUow>().To<Uow>();
// Tell WebApi how to use our Ninject IoC
config.DependencyResolver = new NinjectDependencyResolver(kernel);
}
}
Global.asax
protected void Application_Start()
{
// Tell WebApi to use our custom Ioc (Ninject)
IocConfig.RegisterIoc(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
GlobalConfig.CustomizeConfig(GlobalConfiguration.Configuration);
AreaRegistration.RegisterAllAreas();
}

I have written some gists to help configure Ninject with MVC and Web Api. Simply include the file(s):
https://gist.github.com/odytrice/5821087 (for MVC)
https://gist.github.com/odytrice/5842010 (for WebApi)
To add Bindings for concrete Types, Just put them in the Load() method of the MainModule. You can create as many modules as you like to keep bindings organized. but you'll also have to add them to the array that is returned in the Modules property.
Then Add to the Application_Start() method
NinjectContainer.RegisterModules(NinjectModules.Modules) (for MVC)
NinjectHttpContainer.RegisterModules(NinjectHttpModules.Modules) (for WebApi)
Note that you can use the same NinjectModules.Modules for both the MVC and WebApi registration. I just separated it for clearity
UPDATE: Remember to Remove NinjectWebCommon.cs from your project as it loads and bootstraps a new kernel at Runtime which unfortunately is only for MVC.
UPDATE: You can also use
NinjectContainer.RegisterAssembly() (for MVC)
NinjectHttpContainer.RegisterAssembly() (for WebApi)
This will scan your current assembly for all modules. This way you can put your modules anywhere in your project and it will be registered

With MVC 5 and Web API 2.2 I solved this problem by making sure I included the following NuGet packages:
Ninject.MVC5
Ninject.Web.WebApi.WebHost for Web API
This installed other Ninject dependencies and allowed me to RegisterServices through NinjectWebCommon.cs.

After searching a lot, it turns out there we can't use Ninject with web api and regular mvc. I mean, we have to configure the Repositories separately.
I then found a nice article which explains how you can use Ninject with asp.net mvc & web api: http://www.codeproject.com/Articles/412383/Dependency-Injection-in-asp-net-mvc4-and-webapi-us
And now, I don't get the error and it's working :D
Update 1:
Also try Writing a simple implementation of dependency injection in MVC 4 Web API with .NET Framework 4.5

Here is the simple solution that works fine for me:
In Visual studio, create new web application project named DemoApp and make sure you have selected Empty template with MVC and Web API references:
In Package manager console execute one by one:
Install-Package Ninject
Install-Package Ninject.MVC5
Add NinjectDependencyResolver.cs to IoC folder :
using Ninject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http.Dependencies;
namespace DemoApp.IoC
{
public class NinjectDependencyResolver : IDependencyResolver, System.Web.Mvc.IDependencyResolver
{
private readonly IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return this;
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
public void Dispose() { } //it is not necessary to implement any dispose logic here
}
}
Make the following changes in App_Start/NinjectWebCommon.cs :
Add these lines in CreateKernel method:
NinjectDependencyResolver ninjectResolver = new NinjectDependencyResolver(kernel);
DependencyResolver.SetResolver(ninjectResolver); //MVC
GlobalConfiguration.Configuration.DependencyResolver = ninjectResolver; //Web API
Add your bindings in RegisterServices method like:
kernel.Bind< IHelloService>().To< HelloService>();
Now NinjectWebCommon.cs should look like:
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(DemoApp.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(DemoApp.App_Start.NinjectWebCommon), "Stop")]
namespace DemoApp.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using DemoApp.IoC;
using System.Web.Mvc;
using System.Web.Http;
using DemoApp.Config;
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
NinjectDependencyResolver ninjectResolver = new NinjectDependencyResolver(kernel);
DependencyResolver.SetResolver(ninjectResolver); //MVC
GlobalConfiguration.Configuration.DependencyResolver = ninjectResolver; //Web API
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IHelloService>().To<HelloService>();
}
}
}
Just for the completeness of the example, add some Mvc and Api controllers, and code for IHelloService, HelloService :
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DemoApp.Config;
namespace DemoApp.Controllers
{
public class HomeController : Controller
{
private IHelloService helloService;
public HomeController(IHelloService helloService)
{
this.helloService = helloService;
}
// GET: /Home/
public string Index()
{
return "home/index: " + helloService.GetMessage();
}
}
}
UserController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using DemoApp.Config;
namespace DemoApp.Controllers
{
public class UserController : ApiController
{
private IHelloService helloService;
public UserController(IHelloService helloService)
{
this.helloService = helloService;
}
[HttpGet]
public string Data()
{
return "api/user/data: " + helloService.GetMessage();
}
}
}
IHelloService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace DemoApp.Config
{
public interface IHelloService
{
string GetMessage();
}
}
HelloService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace DemoApp.Config
{
public class HelloService : IHelloService
{
public string GetMessage()
{
return "Hi";
}
}
}
The final structure should look like:
Now make some tests in browser. For me it was:
http://localhost:51156/home/index
http://localhost:51156/api/user/data
And that's it.

I think the issue is that you are not registering a ControllerFactory that uses Ninject to build the controllers (and resolve their dependencies), have you tried implementing your own ControllerFactory yet? See also here http://bubblogging.wordpress.com/2012/06/04/mvc-controller-factory-ninject/.

There is a more elegant solution for this by Nenad - it took me 3 extra hours because I first tried to implement the solutions here conflicting with existing infrastructure I had. It is in reply to another stack overflow question. I am duplicating that answer here just in case it helps others to save the time I lost.
There is a way to share same container between MVC and ASP.NET Web API.
You just need to implement both interfaces.
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver, System.Web.Mvc.IDependencyResolver
{
private readonly IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(this.kernel.BeginBlock());
}
}
Check this article for solution:
Simple Way to share Dependency Resolvers between MVC and Web API

Related

Issue on using AutoMapper in asp.net core

I am following a tutorial on asp.net core and angular. When I add the Automapper inside my Startup class it crashes the dotnet cli and couldn't render the page. This is how I use the Automapper in the Startup:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using aspcoreangular.persistence;
using AutoMapper;
namespace aspcoreangular
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAutoMapper();
services.AddDbContext<VegaDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Default")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
}
}
This is how I use it in the controller. But it doesn't get to this point
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using aspcoreangular.models;
using aspcoreangular.persistence;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace aspcoreangular.Controllers
{
public class MakesController : Controller
{
private readonly VegaDbContext context;
private readonly IMapper mapper;
protected MakesController(VegaDbContext context, IMapper mapper)
{
this.mapper = mapper;
this.context = context;
}
[HttpGet("/api/makes")]
public async Task<IEnumerable<Resources.MakeResource>> GetMakes()
{
var makes = await context.Makes.Include(m => m.Models).ToListAsync();
return mapper.Map<List<Make>, List<Resources.MakeResource>>(makes);
}
}
}
This is the image of the crash:
Can you please help me with this? Thank you.
This my MakeResouce class
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using aspcoreangular.models;
namespace aspcoreangular.Controllers.Resources
{
public class MakeResource
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<ModelResource> Models { get; set; }
public MakeResource()
{
Models = new Collection<ModelResource>();
}
}
}
and in my mappingprofile
using aspcoreangular.Controllers.Resources;
using aspcoreangular.models;
using AutoMapper;
namespace aspcoreangular.ClientApp.Mapping
{
public class MappingProfile : Profile
{
protected MappingProfile()
{
CreateMap<Make, MakeResource>();
CreateMap<Model, ModelResource>();
}
}
}
When AutoMapper maps source object to destination object before mapping itself it has to create an instance of the destination object and then Mapper can map properties using reflection.
And the error says: No parameterless constructor is defined for this object.
That means: AutoMapper kindly asks System.Activator class to create instance of the destination object for him. But System.Activator fails because it can't find public parameterless contructor in destination class (obviously, System.Activator can use constructor with parameters, but AutoMapper hadn't provided any parameters for constructor). And that is why the third line of the Error message comes from Activator.CreateInstance method.
So, to sum up, you should examine Resources.MakeResource class (as destination) for parameterless constructor.
PS. But I can't tell you on Why this exception crashes the whole Application

How can I get user and claim information using action filters?

Right now I am doing this to get the information I need:
In my base controller:
public int roleId { get; private set; }
public int userId { get; private set; }
public void setUserAndRole()
{
ClaimsIdentity claimsIdentity;
var httpContext = HttpContext.Current;
claimsIdentity = httpContext.User.Identity as ClaimsIdentity;
roleId = Int32.Parse(claimsIdentity.FindFirst("RoleId").Value);
userId = Int32.Parse(User.Identity.GetUserId());
}
In my controller methods:
public async Task<IHttpActionResult> getTest(int examId, int userTestId, int retrieve)
{
setUserAndRole();
I wanted the roleId and userId to be available and populated in the constructor of my class but from what I understand the constructor fires before authorization information is available.
Can someone tell me how I could do this with an Action Filter? Ideally I would like the Action Filter to be at the controller level but if not then could it be done at the method level.
I am hoping for some good advice and suggestions. Thank you
Update to show System.Web.Http
#region Assembly System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// C:\H\server\packages\Microsoft.AspNet.WebApi.Core.5.2.2\lib\net45\System.Web.Http.dll
#endregion
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
namespace System.Web.Http.Filters
{
//
// Summary:
// Represents the base class for all action-filter attributes.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IFilter
{
//
// Summary:
// Initializes a new instance of the System.Web.Http.Filters.ActionFilterAttribute
// class.
protected ActionFilterAttribute();
//
// Summary:
// Occurs after the action method is invoked.
//
// Parameters:
// actionExecutedContext:
// The action executed context.
public virtual void OnActionExecuted(HttpActionExecutedContext actionExecutedContext);
public virtual Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken);
//
// Summary:
// Occurs before the action method is invoked.
//
// Parameters:
// actionContext:
// The action context.
public virtual void OnActionExecuting(HttpActionContext actionContext);
public virtual Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken);
}
}
Based on your method signature (and later comments below) the code assumes that you are using Web API and not MVC although this could easily be changed for MVC as well.
I do want to specify that if you look purely at the requirements its how can I create a maintainable piece of code that is reused. In this case the code gets claims based information and injects it into your controllers. The fact that you are asking for a Filter is a technical requirement but I am also going to present a solution that does not use a Filter but an IoC instead which adds some flexibility (IMHO).
Some Tips
Try to always use interfaces when/where possible. It makes for easier unit testing, easier to alter the implementation, etc. I will not go into that all here but here is a link.
In WebAPI and also MVC do not use the System.Web.HttpContext.Current. It is very hard to unit test code that makes use of this. Mvc and Web API have a common abstraction called HttpContextBase, use this when possible. If there is no other way (I have not seen this yet) then use new HttpContextWrapper(System.Web.HttpContext.Current) and pass this instance in to what ever method/class you want to use (HttpContextWrapper derives from HttpContextBase).
Proposed Solutions
These are in no particular order. See end for a basic pro list of each solution.
Web API Filter - exactly what you are asking for. A Web API action filter to inject the claims based information into your Web Api methods.
IoC/DI - A very flexible approach to injecting dependencies into your Controllers and classes. I used AutoFac as the Di framework and illustrate how you can get the claims based info injected into your controller.
Authorization Filter - Essentially an extension on solution 1 but used in a manner in which you can secure access to your Web API interface. As it was not clear how you wanted to use this information I made the jump in this proposal that you wanted it to ensure the user had sufficient privileges.
Common Code
UserInfo.cs
This is common code used in both solutions that I will demo below. This is a common abstraction around the properties / claims based info you want access to. This way you do not have to extend methods if you want to add access to another property but just extend the interface / class.
using System;
using System.Security.Claims;
using System.Web;
using Microsoft.AspNet.Identity;
namespace MyNamespace
{
public interface IUserInfo
{
int RoleId { get; }
int UserId { get; }
bool IsAuthenticated { get; }
}
public class WebUserInfo : IUserInfo
{
public int RoleId { get; set; }
public int UserId { get; set; }
public bool IsAuthenticated { get; set; }
public WebUserInfo(HttpContextBase httpContext)
{
try
{
var claimsIdentity = httpContext.User.Identity as ClaimsIdentity;
IsAuthenticated = httpContext.User.Identity.IsAuthenticated;
if (claimsIdentity != null)
{
RoleId = Int32.Parse(claimsIdentity.FindFirst("RoleId").Value);
UserId = Int32.Parse(claimsIdentity.GetUserId());
}
}
catch (Exception ex)
{
IsAuthenticated = false;
UserId = -1;
RoleId = -1;
// log exception
}
}
}
}
Solution 1 - Web API Filter
This solution demos what you asked for, a reusable Web API filter that populates the claims based info.
WebApiClaimsUserFilter.cs
using System.Web;
using System.Web.Http.Controllers;
namespace MyNamespace
{
public class WebApiClaimsUserFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
// access to the HttpContextBase instance can be done using the Properties collection MS_HttpContext
var context = (HttpContextBase) actionContext.Request.Properties["MS_HttpContext"];
var user = new WebUserInfo(context);
actionContext.ActionArguments["claimsUser"] = user; // key name here must match the parameter name in the methods you want to populate with this instance
base.OnActionExecuting(actionContext);
}
}
}
Now you can use this filter by applying it to your Web API methods like an attribute or at the class level. If you want access everywhere you can also add it to the WebApiConfig.cs code like so (optional).
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new WebApiClaimsUserFilterAttribute());
// rest of code here
}
}
WebApiTestController.cs
Here how to use it in a Web API method. Note that the matching is done based on the parameter name, this has to match the name assigned in the filter actionContext.ActionArguments["claimsUser"]. Your method will now be populated with the added instance from your filter.
using System.Web.Http;
using System.Threading.Tasks;
namespace MyNamespace
{
public class WebApiTestController : ApiController
{
[WebApiClaimsUserFilterAttribute] // not necessary if registered in webapiconfig.cs
public async Task<IHttpActionResult> Get(IUserInfo claimsUser)
{
var roleId = claimsUser.RoleId;
await Task.Delay(1).ConfigureAwait(true);
return Ok();
}
}
}
Solution 2 - IoC / DI
Here is a wiki on Inversion of Control and a wiki on Dependency Injection. These terms, IoC and DI, are usually used interchangeably. In a nutshell you define dependencies, register them with a DI or IoC framework, and these dependency instances are then injected in your running code for you.
There are many IoC frameworks out there, I used AutoFac but you can use whatever you want. Following this method you define your injectibles once and get access to them wherever you want. Just by referencing my new interface in the constructor it will be injected with the instance at run time.
DependencyInjectionConfig.cs
using System.Reflection;
using System.Web.Http;
using System.Web.Mvc;
using Autofac;
using Autofac.Integration.Mvc;
using Autofac.Integration.WebApi;
namespace MyNamespace
{
public static class DependencyInjectionConfig
{
/// <summary>
/// Executes all dependency injection using AutoFac
/// </summary>
/// <remarks>See AutoFac Documentation: https://github.com/autofac/Autofac/wiki
/// Compare speed of AutoFac with other IoC frameworks: http://nareblog.wordpress.com/tag/ioc-autofac-ninject-asp-asp-net-mvc-inversion-of-control
/// </remarks>
public static void RegisterDependencyInjection()
{
var builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterControllers(typeof(DependencyInjectionConfig).Assembly);
builder.RegisterModule(new AutofacWebTypesModule());
// here we specify that we want to inject a WebUserInfo wherever IUserInfo is encountered (ie. in a public constructor in the Controllers)
builder.RegisterType<WebUserInfo>()
.As<IUserInfo>()
.InstancePerRequest();
var container = builder.Build();
// For Web API
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// 2 lines for MVC (not web api)
var resolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(resolver);
}
}
}
Now we just have to call this when our application starts, this can be done in the Global.asax.cs file.
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Http;
namespace MyNamespace
{
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
DependencyInjectionConfig.RegisterDependencyInjection();
// rest of code
}
}
}
Now we can use it where ever we want.
WebApiTestController.cs
using System.Web.Http;
using System.Threading.Tasks;
namespace MyNamespace
{
public class WebApiTestController : ApiController
{
private IUserInfo _userInfo;
public WebApiTestController(IUserInfo userInfo)
{
_userInfo = userInfo; // injected from AutoFac
}
public async Task<IHttpActionResult> Get()
{
var roleId = _userInfo.RoleId;
await Task.Delay(1).ConfigureAwait(true);
return Ok();
}
}
}
Here are the dependencies you can get from NuGet for this example.
Install-Package Autofac
Install-Package Autofac.Mvc5
Install-Package Autofac.WebApi2
Solution 3 - Authorization Filter
One more solution I thought of. You never specified why you needed the user and role id. Maybe you want to check access level in the method before proceeding. If this is the case the best solution is to not only implement a Filter but to create an override of System.Web.Http.Filters.AuthorizationFilterAttribute. This allows you to execute an authorization check before your code even executes which is very handy if you have varying levels of access across your web api interface. The code I put together illustrates the point but you could extend it to add actual calls to a repository for checks.
WebApiAuthorizationClaimsUserFilterAttribute.cs
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http.Controllers;
namespace MyNamespace
{
public class WebApiAuthorizationClaimsUserFilterAttribute : System.Web.Http.Filters.AuthorizationFilterAttribute
{
// the authorized role id (again, just an example to illustrate this point. I am not advocating for hard coded identifiers in the code)
public int AuthorizedRoleId { get; set; }
public override void OnAuthorization(HttpActionContext actionContext)
{
var context = (HttpContextBase) actionContext.Request.Properties["MS_HttpContext"];
var user = new WebUserInfo(context);
// check if user is authenticated, if not return Unauthorized
if (!user.IsAuthenticated || user.UserId < 1)
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, "User not authenticated...");
else if(user.RoleId > 0 && user.RoleId != AuthorizedRoleId) // if user is authenticated but should not have access return Forbidden
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden, "Not allowed to access...");
}
}
}
WebApiTestController.cs
using System.Web.Http;
using System.Threading.Tasks;
namespace MyNamespace
{
public class WebApiTestController : ApiController
{
[WebApiAuthorizationClaimsUserFilterAttribute(AuthorizedRoleId = 21)] // some role id
public async Task<IHttpActionResult> Get(IUserInfo claimsUser)
{
// code will only be reached if user is authorized based on the filter
await Task.Delay(1).ConfigureAwait(true);
return Ok();
}
}
}
Quick Comparison of Solutions
If you want flexibility go with AutoFac. You can reuse this for many of the moving parts of your solution/project. It makes for very maintainable and testable code. You can extend it very easily once its setup and running.
If you want something static and simple that is guaranteed not to change and you have minimal number of moving parts where an DI framework would be overkill then go with the Filter solution.
If you want to execute authorization checks in a single location then a custom AuthorizationFilterAttribute is the best way to go. You can add the code from the filter in solution #1 to this code if authorization passes, this way you still have access to the user information for other purposes in your code.
Edits
I added a 3rd solution to the list of possibilities.
Added a solution summary at the top of the answer.
Create a custom ActionFilter class (for OnActionExecuting):
using System.Security.Claims;
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
namespace YourNameSpace
{
public class CustomActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
ClaimsIdentity claimsIdentity = HttpContext.Current.User.Identity as ClaimsIdentity;
filterContext.ActionParameters["roleId"] = int.Parse(claimsIdentity.FindFirst("RoleId").Value);
filterContext.ActionParameters["userId"] = int.Parse(claimsIdentity.GetUserId());
}
}
}
Then decorate a choice of Base Controller, Controller or Action(s) (depending on the level you want to apply the custom filter), and specify roleId and userId as Action parameters:
[CustomActionFilter]
public async Task<IHttpActionResult> getTest(int roleId, int userId, int examId, int userTestId, int retrieve)
{
// roleId and userId available to use here
// Your code here
}
Hopefully that should do it.

Katana not finding start up method using reflection

I am working through Scott Allen's MVC 5 Fundamentals course on Pluralsight
The following code should work , but when I browse to localhost:8080 I get a blank page
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Owin.Hosting;
using Owin;
namespace ConsoleApplication1
{
using AppFunc = Func<IDictionary<string, object>, Task>;
class Program
{
static void Main(string[] args)
{
string uri = "http://localhost:8080";
using (WebApp.Start<Startup>(uri)) // Katana Please start, using the configuration from the Startup class and listening on the port given by the uri
{
Console.WriteLine("Started!");
Console.ReadKey();
Console.WriteLine("Stopping!");
}
}
}
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use<HelloWorldComponent>();
}
}
public class HelloWorldComponent
{
AppFunc _next;
public HelloWorldComponent(AppFunc next)
{
_next = next;
}
// Katana uses reflection to find this Invoke function that matches the AppFunc signature
public Task Invoke(IDictionary<string, object> environment)
{
var response = environment["owin.ResonseBody"] as Stream;
using (var writer = new StreamWriter(response))
{
return writer.WriteAsync("Hello");
}
}
}
}
How do I get it working?
Everything is setup correctly, there is just a small typo in fetching the response object:
var response = environment["owin.ResponseBody"] as Stream;
using (var writer = new StreamWriter(response))
{
return writer.WriteAsync("Hello");
}
Notice the "p" in "ResponseBody"!

Where to do DBContext.SaveChanges() if I'm using InRequestScope()

I'm developing an ASP.NET MVC 5 Web API application with C#, .NET Framework 4.5.1, Entity Framework 6.1.1 and the latest version of Ninject (I have also installed Ninject.MVC5).
I'm learning how to implement dependency injection, and I think I have learned it, but I have a question. These are my interfaces and classes.
Unit of work interface:
public interface IUnitOfWork
{
void Commit();
}
Custom DbContext implementation (I use IUnitOfWork interface to allow DI):
public class EFDbContext : DbContext, IUnitOfWork
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
[ ... ]
}
public void Commit()
{
this.SaveChanges();
}
}
And this is how allow Dependency Injection with Ninject and Ninject.Web.Common.
I have a class, NinjectConfigurator, that adds bindings:
public class NinjectConfigurator
{
public void Configure(IKernel container)
{
// Add all bindings/dependencies
AddBindings(container);
// Use the container and our NinjectDependencyResolver as
// application's resolver
var resolver = new NinjectDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
private void AddBindings(IKernel container)
{
ConfigureLog4net(container);
container.Bind<IUnitOfWork>().To<EFDbContext>().InRequestScope();
container.Bind<IGenericRepository<User>>().To<GenericRepository<User>>();
}
private void ConfigureLog4net(IKernel container)
{
log4net.Config.XmlConfigurator.Configure();
var loggerForWebSite = LogManager.GetLogger("MattSocialNetworkWebApi");
container.Bind<ILog>().ToConstant(loggerForWebSite);
}
}
And finally, I have this on NinjectWebCommon:
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
var containerConfigurator = new NinjectConfigurator();
containerConfigurator.Configure(kernel);
}
I use .InRequestScope() because I want a EFDbContext instance per request.
My question is: When do I have to do EFDbContext.SaveChanges()? If I'm using one instance per request I think I have to save the changes at the end of the request, isn't it?
Where do I have to put EFDbContext.Commit()?
The way I do it, and have seen done other places, is to either commit in your business layer, or in your controller, after each transaction. That means sometimes SaveChanges() will be called more than once per request, but that shouldn't be a significant problem.
I've learned a lot from looking at the code for SocialGoal, which can be found here. It uses Autofac for DI, but it's the same principles as your own code. Maybe you can get some inspiration and answers there too.

sharp architecture question

I am trying to get my head around the sharp architecture and follow the tutorial. I am using this code:
using Bla.Core;
using System.Collections.Generic;
using Bla.Core.DataInterfaces;
using System.Web.Mvc;
using SharpArch.Core;
using SharpArch.Web;
using Bla.Web;
namespace Bla.Web.Controllers
{
public class UsersController
{
public UsersController(IUserRepository userRepository)
{
Check.Require(userRepository != null,"userRepository may not be null");
this.userRepository = userRepository;
}
public ActionResult ListStaffMembersMatching(string filter) {
List<User> matchingUsers = userRepository.FindAllMatching(filter);
return View("ListUsersMatchingFilter", matchingUsers);
}
private readonly IUserRepository userRepository;
}
}
I get this error:
The name 'View' does not exist in the current context
I have used all the correct using statements and referenced the assemblies as far as I can see. The views live in Bla.Web in this architecture.
Can anyone see the problem?
Thanks.
Christian
You should inherit UsersController from System.Web.Mvc.Controller class. View() method is defined in Controller class.
public class UsersController : Controller
{
//...
}

Resources