I have an attribute for my web api authentication:
public class ApiAuthenticationAttribute : ActionFilterAttribute
{
private IApiAuthentication AuthenticationProvider { get; set; }
public ApiAuthorizeAttribute(Type apiAuthorizationType)
{
AuthenticationProvider = (IApiAuthentication)Activator.CreateInstance(apiAuthorizationType);
}
....
}
In this attribute i have the IApiAuthentication type that will do authentication logic.
For passing a concrete type of IApiAuthentication to the attribute I pass in the Type like this:
[ApiAuthentication(typeof(ApiAuthentication))]
I want to know is there a better way to do this?
Related
I have a clean architecture project that provide micro services, one of which is to access Agresso ERP web services.
https://***************/service.svc
it provide many services
https://**/service.svc?FooService/Foo
https://**/service.svc?BooService/Boo
each of which has it's own service reference(connected service), and each of which has many methods.
each call to any of the end point you need to pass credentials with it.
var fooSoapClient = new FooSoapClient();
var credentials = new WSCredentials
{
Username = "fakeuser",
Password = "fakepassword",
Client = "fakeclient",
};
var result = fooSoapClient.GetFoosAsync(Foo filter,true,
credentials );
(P.S) credential class exist in all entities
namespace Foo1NS
{
public partial class WSCredentials : object
{
public string Username {get;set;}
public string Client {get;set;}
public string Password {get;set;}
}
}
namespace Foo2NS
{
public partial class WSCredentials : object
{
public string Username {get;set;}
public string Client {get;set;}
public string Password {get;set;}
}
}
i can access all end points with no problem.
I have the following Questions:
Is there a generic solution i can follow for not to Fall in DRY?
is there a design pattern that best target this issue?
Here is what I've done in the past, it fits in well into Dependency Injection/containers if you use that as well. The key thing here is to define an single interface that all services will implement. Your code that uses this should only be using the interface.
Each class should implement an interface you define, e.g. IWebServiceOperations
public interface IWebServiceOperations
{
WebServiceOperationResult GetFooAsync(WebServiceOperationRequest request);
}
I'll leave you to figure out the classes WebServiceOperationResult/Request, they just hold your request/response variables, including credentials.
Then each webservice you need to implement is done in a separate class. You also dictate in the constructor what type of implementation this is (FooSoap1 vs FooSoap2) e.g.
public class FooSoapClient : BaseClient, IWebServiceOperations
{
public FooSoapClient() : base(Clients.FooSoap1)
public GetFooAsync(...)
{
...
}
}
public class BaseClient
{
private readonly eFooServiceType _serviceType;
public eFooServiceType ServiceType {
get{
return _serviceType;
}
}
protected BaseClient(eFooServiceType service)
{
_serviceType = service;
}
}
Now you should have a bunch of class references. Either your DI container can resolve these for you, based on the service type you want, or you could add them to a Dictionary, so if you wanted to operate against FooSoap1, you'd do...
var fooSoapClient1 = myServices[Clients.FooSoap1];
await fooSoapClient1.GetFooAsync(...)
I have my API route attribute class like this
public class MyRouteAttribute : RouteAttribute
{
private const string BaseRoute = "api/default";
private const string PrefixRouteBase = BaseRoute + "/";
public MyRouteAttribute() : base(BaseRoute)
{
}
public MyRouteAttribute(string route):
base(string.IsNullOrEmpty(route) ?
BaseRoute : PrefixRouteBase + route)
{
}
}
And it is used in controller like this
[MyRoute]
public class MyController : Controller
{
.....
}
How do I pass IOptions to MyRoute if I have to make the route configurable?
For example, if I do this:
public class MyRouteAttribute : RouteAttribute
{
private const string BaseRoute = "api/default";
public MyRouteAttribute(IOptions<ApiRouteBaseConfiguration> routeOptions) :
base(routeOptions.Value.Url)
{
}
public MyRouteAttribute(IOptions<ApiRouteBaseConfiguration> routeOptions, string route):
base(string.IsNullOrEmpty(route) ? (routeOptions.Value.Url: $"{routeOptions.Value.Url}/" + route)
{
}
}
Then I get error here [MyRoute] asking me to pass IOptions.
How do I access configuration in MyRoute attribute
Attribute instances are created by CLR when attributes are requested from Reflection routines. You have no way to force instantiation of attributes via any DI container.
I see two possible approaches to workaround your challenge. Both of them allow you to have configurable attribute, however configuration is set not via attribute constructor.
The simpler way is to set configuration through static property loaded on application startup:
public class MyRouteAttribute : RouteAttribute
{
public static ApiRouteBaseConfiguration RouteConfiguration { get; } = new ApiRouteBaseConfiguration();
public MyRouteAttribute() :
base(RouteConfiguration.Url)
{
}
public MyRouteAttribute(string route) :
base(string.IsNullOrEmpty(route) ? RouteConfiguration.Url : $"{RouteConfiguration.Url}/" + route)
{
}
}
Configuration (Configuration section is named "Routing" here):
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
Configuration.Bind("Routing", MyRouteAttribute.RouteConfiguration);
}
Well, this solution is not perfect because of static property usage. However it's quite simple and should do the trick.
The second possible approach - use Property Injection pattern for attribute configuration and set it in custom implementation of IApplicationModelProvider. Such approach is described in this answer, I will not duplicated the code here.
Is it possible to have a ActionFilterAttribute parameters like this ?
[DataType(DataType.Password)]
For example I need to create something like this
[ValidateSession(Session.Required)]
public class ValidateSession : ActionFilterAttribute
{
enum Session
{
Required,
NotRequired
}
private Session _session { get; set; }
public ValidateSession(Session session)
{
this._session = session;
}
}
You can add parameters to custom ActionFilter. For more information see
this.
The API Call
I am making a REST API call with the following message body:
{"Method":{"Token":"0","Value":"0"}}
400 Response
I am getting a 400 Bad Request response from the api with the following body:
{"Message":"The request is invalid.","ModelState":{"request.Method.Token":["Could not create an instance of type Namespace.ActionMethod. Type is an interface or abstract class and cannot be instantiated. Path 'ActionMethod.Token'."]}}
Code Information
The method which is receiving the api call looks like this:
public MethodResponse MakeMethodCall([Required] [FromBody] MethodRequest request)
MethodRequest has a Method property which is an abstract type.
public class MethodRequest
{
public ActionMethod Method { get; set; }
}
public abstract class ActionMethod
{
public string Token { get; set; }
}
public class FirstMethod : ActionMethod
{
public string Value { get; set; }
}
Question
How can I call the REST API and have it recognize that the type of Method is FirstMethod, instead of it trying to instantiate the abstract type ActionMethod?
Note that I will need to have more implementations of ActionMethod in the future (ie. SecondMethod), so the solution will need to include an extensible ActionMethod (interface would also be fine).
EDIT
It would also be reasonable to include an enum to identify which implementation of ActionMethod was being targeted by the API call.
I'm currently using a solution which has an ActionMethodType enum and both FirstMethod and SecondMethod fields. I'm checking these fields based on the value of ActionMethodType. This works, but I would like to have a single [Required] field into which I could pass any implementation of ActionMethod.
Can't be done. How would the framework know to instantiate FirstMethod for this parameter? What if you had another subclass of ActionMethod that also had a Value property? Now it's even more ambiguous for the framework to figure out on it's own. You could do a bunch of work, creating a custom formatter (http://blogs.msdn.com/b/jmstall/archive/2012/04/16/how-webapi-does-parameter-binding.aspx) but ultimately it would be easier to just have a single class that includes all possible properties a client could send OR have separate API endpoints for the client to call using different concrete types as the parameter.
If I understand you correctly, you could implement this with a custom model binder and a factory pattern.
public class MethodRequestBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
HttpRequestBase request = controllerContext.HttpContext.Request;
//use the request object to make a call to your factory for the
//appropriate ActionMethod subtype you want to create, or however
//else you see fit.
var curActionMethod = MyFactory.Get(request.QueryString);
var boundObj = new MethodRequest()
{
Method = curActionMethod
}
return boundObj;
}
}
register your model binder in app_start:
ModelBinders.Binders.Add(typeof(MethodRequest), new MethodRequestBinder());
now, just decorate your controller action method:
public ActionResult Index([ModelBinder(typeof(MethodRequestBinder))] MethodRequest request)
{
//etc..
}
I used this as a starting point: http://www.codeproject.com/Articles/605595/ASP-NET-MVC-Custom-Model-Binder
Remove the abstract keyword from your ActionMethod, or mark the Token property abstract and override it in the inherited classes:
public abstract class ActionMethod
{
public abstract string Token { get; set; }
}
public class FirstMethod : ActionMethod
{
public string Value { get; set; }
public override string Token
{
get;
set;
}
}
I'musing ASP.NET Web API and I need to have authorization so I've created custom authorization attribute
public class CustomAuthorizationAttribute : AuthorizeAttribute
In order to inject dependency inside constructor I have following :
public CustomAuthorizationAttribute(IAccountBL accountBl)
{
_accountBL = accountBl;
}
In IAccountBL I have method which interacts with database checking if user is authorized to make request.
Inside Member API controller I've register that attribute
[CustomAuthorization]
public class MemberController : ApiController
But I get following error
Project.Account.AccountBL' does not contain a constructor that takes 0 arguments
And if I register it like
[CustomAuthorization(IAccountBL)]
Thank you
Action filters are just attributes. You do not have control over when those attributes are instantiated by the CLR. One possibility is to write a marker attribute:
public class CustomAuthorizationAttribute : Attribute { }
and then the actual action filter:
public class CustomAuthorizationFilter : ActionFilterAttribute
{
private readonly IAccountBL accountBL;
public CustomAuthorizationFilter(IAccountBL accountBL)
{
this.accountBL = accountBL;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<CustomAuthorizationAttribute>().Any() ||
actionContext.ActionDescriptor.GetCustomAttributes<CustomAuthorizationAttribute>().Any())
{
// here you know that the controller or action is decorated
// with the marker attribute so that you could put your code
}
}
}
and finally register it as a global action filter:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
...
IAccountBL accountBL = ...
config.Filters.Add(new CustomAuthorizationFilter(accountBL));
}
}
and finally you could use the marker attribute:
[CustomAuthorization]
public class MemberController : ApiController
{
...
}
You can get dependency in your filter by using extension method GetDependencyScope for class HttpRequestMessage. It's not a canonical way for dependency injection, but can be used as workaround. A basic example may look like this:
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
var dependencyScope = context.Request.GetDependencyScope();
var dependency = dependencyScope.GetService(typeof (MyDependencyType));
//use your dependency here
}
This method may be used with constructor injection to simplify unit testing:
public class MyAuthenticationFilter : Attribute, IAuthenticationFilter
{
private Func<HttpRequestMessage, MyDependencyType> _dependencyFactory;
public MyAuthenticationFilter() :
this(request => (MyDependencyType)request.GetDependencyScope().GetService(typeof(MyDependencyType)))
{
}
public MyAuthenticationFilter(Func<HttpRequestMessage, MyDependencyType> dependencyFactory)
{
_dependencyFactory = dependencyFactory;
}
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
var dependencyScope = context.Request.GetDependencyScope();
var dependency = dependencyFactory.Invoke(context.Request);
//use your dependency here
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public bool AllowMultiple { get; private set; }
}
If anyone finds similar issue here's how I manage to solve it.
My custom filter inherits IAutofacAuthorizationFilter. Besides this one you can also inherit IAutofacExceptionFilter and IAutofacActionFilter.
And inside my DI container I've register this filter for each controller I want to use like this
builder.Register(c => new CustomAuthorizationAttribute(c.Resolve<IAccountBL>()))
.AsWebApiAuthorizationFilterFor<MemberController>()
.InstancePerApiRequest();
If you registered your service on the application using any container, it's very easy to get the instance of your service from anywhere in the scope. Just follow the below code to get your service.
var myService = DependencyResolver.Current.GetService(typeof(IMyService)) as IMyService;
Please make sure you have included System.Web.Mvc in the file.
Happy coding!!!