How can I get user and claim information using action filters? - asp.net

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.

Related

System.NotSupportedException when calling OData service from NetCoreApp2.1

I have set up a multi targetting (net4.5.2/netstandard2) class library allowing to consume one of our enterprise OData services.
To access this OData service we use a proxy class generated with the OData v4 Client Code Generator (v7.5.0)
Unfortunately, when trying to use my library in a Netcoreapp2.1 application I encounter an issue as soon as I try to enumerate a collection.
Container.MyDataSet.ToList(); produces the following exception :
"System.NotSupportedException : This target framework does not enable
you to directly enumerate over a data service query. This is because
enumeration automatically sends a synchronous request to the data
service. Because this framework only supports asynchronous operations,
you must instead call the BeginExecute and EndExecute methods to
obtain a query result that supports enumeration."
I do not encounter this issue when using this same multitarget library in a .Net 4.5.2 application.
Having a look at the Microsoft.OData.Client v7.5.0 source code, this behaviour seems to be by design with specific handling of the .Net Core case.
Did I miss something ?
The following code prevents the issue, but it is barely usable :
var query = (DataServiceQuery<MyData>)Container.MyDataSet;
var taskFactory = new TaskFactory<IEnumerable<MyData>>();
var t = taskFactory.FromAsync(query.BeginExecute(null, null), data => query.EndExecute(data));
t.ConfigureAwait(false);
IEnumerable<MyData> result = t.Result;
How can I use an OData IQueryable in .Net Core application without adding specific code ?
As mentioned in the error message, the platform only supports asynchronous fetches. Even after you use that, you will likely need to enumerate over the results multiple times -- everytime you perform a ToList(), FirstOrDefault() or other similar System.Generics.Collections operations, you are essentially getting the Enumerator of the collection and enumerating over it.
I adopted this solution: immediately after I fetch enumerable results from the OData libraries I enumerate over them and put them in another enumerable container (Dictionary<string, MyAwesomeResult> in this case) instantiated by me.
var resultsQuery = this.oDataClient.MyAwesomeResults
.AddQueryOption("$filter", "Name eq 'MyAwesomeName'")
.AddQueryOption("$top", "5")
.AddQueryOption("$skip", "2");
IEnumerable<MyAwesomeResult> resultsRaw = await
resultsQuery.ExecuteAsync();
var results = new Dictionary<string, MyAwesomeResult>();`
foreach (var resultRaw in resultsRaw)
{
results.Add(resultRaw.Key, resultRaw);
}
Then I use the container I instantiated -- I no longer need to enumerate again over the enumerable returned by
DataServiceQuery<MyAwesomeResult>.ExecuteAsync.
As said by #PanagiotisKanavos DataServiceQuery.ToString() will return the uri of the OData query.
Based on this, I wrote my own IQueryable :
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.OData.Client;
public class ODataLinqQuery<T> : IOrderedQueryable<T>
{
public IQueryProvider Provider { get; }
private DataServiceQuery<T> DataServiceQuery { get; }
public ODataLinqQuery(DataServiceQuery<T> dataServiceQuery, MyClient client, Type finalType)
{
this.DataServiceQuery = dataServiceQuery;
this.Provider = new ODataLinqQueryProvider<T>(dataServiceQuery, client, finalType);
}
public IEnumerator<T> GetEnumerator()
{
return this.Provider.Execute<IEnumerable<T>>(this.Expression).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.Provider.Execute<System.Collections.IEnumerable>(this.Expression).GetEnumerator();
}
public Expression Expression => this.DataServiceQuery.Expression;
public Type ElementType => typeof(T);
}
Where MyClient is an utility class which wraps an HttpClient, handles authentication token, and performs result deserialization.
FinalType is to keep track on the type I want to obtain and deserialize, as I am handling IQueryables over interfaces.
Then I wrote my own IQueryProvider :
using System;
using System.Collections;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;
using Microsoft.OData.Client;
public class ODataLinqQueryProvider<T> : IQueryProvider
{
private MyClient Client { get; set; }
private DataServiceQuery<T> DataServiceQuery { get; set; }
private Type FinalType { get; }
public ODataLinqQueryProvider(
DataServiceQuery<T> dsq,
MyClient client,
Type finalType)
{
this.DataServiceQuery = dsq;
this.Client = client;
this.FinalType = finalType;
}
public IQueryable CreateQuery(Expression expression)
{
return new ODataLinqQuery<T>(this.DataServiceQuery, this.Client, this.FinalType);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
var pro = new DataServiceQuery<TElement>(expression, this.DataServiceQuery.Provider as DataServiceQueryProvider);
return new ODataLinqQuery<TElement>(pro, this.Client, this.FinalType);
}
public object Execute(Expression expression)
{
this.DataServiceQuery = new DataServiceQuery<T>(expression, this.DataServiceQuery.Provider as DataServiceQueryProvider);
return this.Execute();
}
public TResult Execute<TResult>(Expression expression)
{
this.DataServiceQuery = new DataServiceQuery<T>(expression, this.DataServiceQuery.Provider as DataServiceQueryProvider);
var res = this.Execute();
if (typeof(IEnumerable).IsAssignableFrom(typeof(TResult)))
{
return (TResult)res;
}
else
{
return ((IEnumerable)res).Cast<TResult>().FirstOrDefault();
}
}
private object Execute()
{
var result = Client.GetResult(typeof(OData<>).MakeGenericType(this.FinalType), HttpMethod.Get, new Uri(this.DataServiceQuery.ToString())) as OData;
return result.Objects;
}
}
Where Odata<> class is just for deserialization of the OData result and GetResult "just" invokes the GetAsync method of its underlying HttpClient with the correct authentication headers, wait for and deserializes the result :
using System.Collections.Generic;
using Newtonsoft.Json;
public class OData<T> : OData where T : class
{
public override IEnumerable<object> Objects => this.Value;
public List<T> Value { get; set; }
}
public class OData
{
[JsonProperty("#odata.context")]
public string Metadata { get; set; }
public virtual IEnumerable<object> Objects { get; set; }
}
Finally I expose my IQueryable as follows :
var myQueryable = new ODataLinqQuery<MyData>(this.Container.MyDataSet, myclient, typeof(MyData));
I can then apply filters, orderby, top and skip and get the results as with a standard IQueryable. I know that this implementation is not complete, and IQueryable to OData is not as complete as most IQueryable to SQL, but it achieves the minimum I need.

how implement exiting authentication roles in the database into AspNet IdentityRole

i've asp mvc application , database first , i have a table to hold my roles another for my users and junction table user_role.
i added the following class to my app
Microsoft.AspNet.Identity.Owin
Microsoft.AspNet.Identity.EntityFramework
Microsoft.Owin.Host.SystemWeb
can i use my existing tables to apply the roles to my controllers
[Authorize(Roles = "Admin")]]
public ActionResult MySecretAction() {}
or maybe
[Authorize(Roles = MyDBEntities.Roles.Find(1)]]
public ActionResult MySecretAction() {}
thank you
Can I use existing roles from db table?
Yes you can use existing roles from database.
You can use [Authorize(Roles = "Admin")], but not [Authorize(Roles = MyDBEntities.Roles.Find(1)] as it is not constant value, but dynamic.
But how can I add and remove roles to my existing tables when I assign a role to a user?
To add new role(s) you have to use RoleManager class with CreateAsync method along with other methods for managing roles used by your app.
When i add a role to a method , and the user is not authorized to use it , the application redirects him back to the login page ,where to change this?
To alter behavior during athorization you have to implement own Authorization attribute inherited from AuthorizeAttribute and override OnAuthorization method.
public class AuthorizeRoleAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
// User is not authenticated(NOT logged in)
// we are letting ASP.NET to use standard procedure => redirect her/him to login page
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
base.HandleUnauthorizedRequest(filterContext);
}
// User is authenticated(logged in)
// we are going to show her/him custom view with error
else
{
// Don't forget to create Unauthorized.cshtml view in Shared folder
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Shared/Unauthorized.cshtml"
};
}
}
}
Then you have to use your custom AuthorizeRoleAttribute instead the default one.
[AuthorizeRole(Roles = "Admin")]]
public ActionResult MySecretAction() {}
Resources:
RoleManager class
Implementing RoleManager in ASP.NET MVC 5
ASP.NET MVC 5 Identity: Extending and Modifying Roles
I've created a costume authorization class , witch i can user to access the logged in user and my databases tables
using System;
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using System.Linq;
using System.Collections.Generic;
using LoanApp.Models.DataBaseModel;
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class DynamicAuthorize : AuthorizeAttribute
{
// public string DefaultURL { get; set; }
protected override bool AuthorizeCore(HttpContextBase context)
{ return true;
}
}

How to rewrite code to use IAuthorizationFilter with dependency injection instead of AuthorizeAttribute with service location in Asp Net Web Api?

I have the custom AuthorizeAttribute where I need to use one of the business layer services to validate some data in the database before giving user a permission to view the resource. In order to be able to allocate this service within the my AuthorizeAttribute I decided to use service location "anti-pattern", this is the code:
internal class AuthorizeGetGroupByIdAttribute : AuthorizeAttribute
{
private readonly IUserGroupService _userGroupService;
public AuthorizeGetGroupByIdAttribute()
{
_userGroupService = ServiceLocator.Instance.Resolve<IUserGroupService>();
}
//In this method I'm validating whether the user is a member of a group.
//If they are not they won't get a permission to view the resource, which is decorated with this attribute.
protected override bool IsAuthorized(HttpActionContext actionContext)
{
Dictionary<string, string> parameters = actionContext.Request.GetQueryNameValuePairs().ToDictionary(x => x.Key, x => x.Value);
int groupId = int.Parse(parameters["groupId"]);
int currentUserId = HttpContext.Current.User.Identity.GetUserId();
return _userGroupService.IsUserInGroup(currentUserId, groupId);
}
protected override void HandleUnauthorizedRequest(HttpActionContext actionContex)
{
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
base.HandleUnauthorizedRequest(actionContex);
}
else
{
actionContex.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
}
}
}
I have couple of other attributes like this in my application. Using service locator is probably not a good approach. After searching the web a little bit I found some people suggesting to use IAuthorizationFilter with dependency injection instead. But I don't know how to write this kind of IAuthorizationFilter. Can you help me writing IAuthorizationFilter that will do the same thing that the AuthorizeAttribute above?
So after struggling for a while I think I managed to resolve this issue. Here are the steps you have to do in order to that:
1) First you have to make GetGroupByIdAttribute passive, and by passive I mean an empty attribute without any logic within it (it will be used strictly for decoration purposes)
public class GetGroupByIdAttribute : Attribute
{
}
2) Then you have to mark a controller method, for which you want to add authorization, with this attribute.
[HttpPost]
[GetGroupById]
public IHttpActionResult GetGroupById(int groupId)
{
//Some code
}
3) In order to write your own IAuthorizationFilter you have to implement its method ExecuteAuthorizationFilterAsync. Here is the full class (I included comments to guide you through the code):
public class GetGroupByIdAuthorizationFilter : IAuthorizationFilter
{
public bool AllowMultiple { get; set; }
private readonly IUserGroupService _userGroupService;
//As you can see I'm using a constructor injection here
public GetGroupByIdAuthorizationFilter(IUserGroupService userGroupService)
{
_userGroupService = userGroupService;
}
public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
//First I check whether the method is marked with the attribute, if it is then check whether the current user has a permission to use this method
if (actionContext.ActionDescriptor.GetCustomAttributes<GetGroupByIdAttribute>().SingleOrDefault() != null)
{
Dictionary<string, string> parameters = actionContext.Request.GetQueryNameValuePairs().ToDictionary(x => x.Key, x => x.Value);
int groupId = int.Parse(parameters["groupId"]);
int currentUserId = HttpContext.Current.User.Identity.GetUserId();
//If the user is not allowed to view view the resource, then return 403 status code forbidden
if (!_userGroupService.IsUserInGroup(currentUserId, groupId))
{
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.Forbidden));
}
}
//If this line was reached it means the user is allowed to use this method, so just return continuation() which basically means continue processing
return continuation();
}
}
4) The last step is to register your filter in the WebApiConfig.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Here I am registering Dependency Resolver
config.DependencyResolver = ServiceLocator.Instance.DependencyResolver;
//Then I resolve the service I want to use (which should be fine because this is basically the start of the application)
var userGroupService = ServiceLocator.Instance.Resolve<IUserGroupService>();
//And finally I'm registering the IAuthorizationFilter I created
config.Filters.Add(new GetGroupByIdAuthorizationFilter(userGroupService));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Now, if needed, I can create additional IActionFilters that use IUserGroupService and then inject this service at the start of the application, from WebApiConfig class, into all filters.
Perhaps try it like shown here:
Add the following public method to your class.
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
// gets the dependecies from the serviceProvider
// and creates an instance of the filter
return new GetGroupByIdAuthorizationFilter(
(IUserGroupService )serviceProvider.GetService(typeof(IUserGroupService )));
}
Also Add interface IFilterMetadata to your class.
Now when your class is to be created the DI notices that there is a CreateInstance method and will use that rather then the constructor.
Alternatively you can get the interface directly from the DI in your method by calling
context.HttpContext.Features.Get<IUserGroupService>()

Create/Get DefaultHtmlGenerator from MVC Controller

I am trying to create(Or get an instance of it somehow) for Microsoft.AspNet.Mvc.Rendering.DefaultHtmlGenerator inside my MVC6 controller method
I wanted to generate the html for validation for my Model my self inside my controller of asp.net mvc. My issue is where to get the constructor data for DefaultHtmlGenerator like antiforgery, metadataProvider..etc
[HttpGet]
public IActionResult GetMarkup()
{
// IHtmlGenerator ge = this.CurrentGenerator();
IHtmlGenerator ge = new DefaultHtmlGenerator(params);
var tag= ge.GetClientValidationRules(params)
}
here is the a link about the HtmlGenerator class
DefaultHtmlGenerator
Since MVC 6 is based on dependency injection, all you have to do is require IHtmlGenerator in your constructor, and the DI container will automatically fill in all of the dependencies of DefaultHtmlGenerator (provided that is what is setup in your DI configuration).
public class HomeController : Controller
{
private readonly IHtmlGenerator htmlGenerator;
public HomeController(IHtmlGenerator htmlGenerator)
{
if (htmlGenerator == null)
throw new ArgumentNullException("htmlGenerator");
this.htmlGenerator = htmlGenerator;
}
public IActionResult GetMarkup()
{
// Use the HtmlGenerator as required.
var tag = this.htmlGenerator.GetClientValidationRules(params);
return View();
}
}
That said, it appears that the GetClientValidationRules method is only designed to work within a view, since it accepts ViewContext as a parameter. But this does answer the question that you asked.

Configuring Ninject with Asp.Net MVC & Web Api

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

Resources