I want to dependency inject an attribute in ASP.NET MVC using Spring.Net, my attribute is something like this (note this is all pseudo code I've just typed in)...
public class InjectedAttribute : ActionFilterAttribute
{
private IBusinessLogic businessLogic;
public InjectedAttribute(IBusinessLogic businessLogic)
{
this.businessLogic = businessLogic;
}
public override void OnActionExecuting(ActionExecutedContext filterContext)
{
// do something with the business logic
businessLogic.DoSomethingImportant();
}
}
I'm using a controller factory to create the Controllers which are also injected with various business logic objects. I'm getting the controllers from the IoC container like this...
ContextRegistry.GetContext().GetObject("MyMVCController");
I'm configuring my Controllers like so passing in the business logic
<object name="MyMVCController" type="MyMVC.MyMVCController, MyMVC">
<constructor-arg index="0" ref="businessLogic" />
</object>
Is there a way to configure the injection of the attributes? I don't really want to put this into my attributes...
public class InjectedAttribute : ActionFilterAttribute
{
private IBusinessLogic businessLogic;
public InjectedAttribute(IBusinessLogic businessLogic)
{
this.businessLogic = ContextRegistry.GetContext().GetObject("businessLogic");
}
....
I'm configuring my Controllers like so passing in the business logic
This defines controllers as singletons meaning that they will be reused among all requests which could be catastrophic. Ensure controllers are not defined as singletons:
<object name="AnotherMovieFinder" type="MyMVC.MyMVCController, MyMVC" singleton="false">
<constructor-arg index="0" ref="businessLogic" />
</object>
Now, this being said let's go back to the main question about attributes.
Because you want constructor injection in your filters you can no longer decorate any controllers or actions with them as attribute values must be known at compile time. You need a mechanism to apply those filters at runtime to controllers/actions.
If you are using ASP.NET MVC 3 you could write a custom filter provider which will apply your action filter to desired controllers/actions by injecting dependencies into it.
If you are using an older version you could use a custom ControllerActionInvoker.
Related
So I have a need for injecting a number of different services into an authorization attribute I'm using. For simplicity I will leave this to show the configuration manager.
public class FeatureAuthorizeAttribute : AuthorizeAttribute
{
public IConfigurationManager ConfigurationManager;
private readonly string _feature;
public FeatureAuthorizeAttribute(string feature)
{
_feature = feature;
var test = ConfigurationManager.GetCdnPath();
}
}
Which would be used as follows
[FeatureAuthorize("Admin")]
I have tried to use constructor injection
public FeatureAuthorizeAttribute(string feature, IConfigurationManager configurationManager)
{
ConfigurationManager = configurationManager;
_feature = feature
}
However this just causes an error when I attempt
[FeatureAuthorize("Admin", IConfigurationManager)]
Which seems like the wrong way to go about it in the first place. I'm assuming that I need to register my custom authorization attribute with the container to get it to start picking up
Instead of trying to use Dependency Injection with attributes (which you can't do in any sane, useful way), create Passive Attributes.
Specifically, in this case, assuming that this is an ASP.NET MVC scenario, you can't derive from AuthorizeAttribute. Instead, you should make your Authorization service look for your custom attribute, and implement IAuthorizationFilter. Then add the filter to your application's configuration.
More details can be found in this answer: https://stackoverflow.com/a/7194467/126014.
Struts 2, 2.3.20 mentioned that
Support for accessing static methods from expression will be disabled
soon, please consider re-factoring your application to avoid further
problems!
We have used OGNL static calls in validators:
#ExpressionValidator(
expression = "#foo.bar#isValidAmount(amount)",
key = "validate.amount.is.not.valid"),
Also we used it in tags
<s:set var="test"
value="#foo.bar#sampleMethod(#attr.sampleObject.property1)" />
Well, what is the best way to refactor above two usages ?!
In your code you are using a static method call. The best way is to create a method in the action class that wraps a static methods and use it in OGNL.
public class Wrapper {
public boolean isValidAmount(amount){
return foo.barr.isValidAmount(amount);
}
public Object sampleMethod(Object property1){
return foo.barr.sampleMethod(Object property1);
}
}
As soon as action bean is in the value stack you can use
#ExpressionValidator(
expression = "isValidAmount(amount)",
key = "validate.amount.is.not.valid"),
or in JSP
<s:set var="test"
value="sampleMethod(#attr.sampleObject.property1)" />
I'm using feature flags to selectively enable/disable certain aspects of my MVC4 web application in different environments. I have an interface named IConfiguration with a IsEnabled(FeatureFlag) method that provides access to these flags.
To this end, I want to disable certain MVC action methods when the feature they relate to is turned off. I have an attribute named FeatureAttribute defined like this:
// Usage: [Feature(FeatureFlag.I18N)]
public class FeatureAttribute : ActionMethodSelectorAttribute {
private IConfiguration _config;
private FeatureFlag _feature;
public FeatureAttribute(FeatureFlag feature) {
_config = DependencyResolver.Current.GetService<IConfiguration>();
_feature = feature;
}
public override bool IsValidForRequest(ControllerContext controllerContext,
MethodInfo methodInfo) {
return _config.IsEnabled(_feature);
}
}
This works, but using DependencyResolver to get an instance of IConfiguration smells funny. Is there any way I can redesign my code to avoid the Service Locator pattern?
I initially thought of using filter injection, but ActionMethodSelectorAttribute is not actually a filter, so it doesn't apply here.
Attributes are created by the .NET Framework. So you can't do Constructor injection. The only two ways to inject into Attributes is to do PropertyInjection or ServiceLocation.
PropertyInjection can be done like this:
Add a IPlanningStrategy that does the scanning with reflection for your attribute (or ActionMethodSelectorAttribute). Return immediatly if not a controller.
Foreach method that has this attribute add a IDirective that contains a reference to the MethodInfo
Add A IActivationStrategy that injects the attribute using kernel.Inject(attribute).
Best you have a look at the PropertyInjection implementation of Ninject it works exactly like this. It just needs some changes to do what you want.
To begin with two things.
I am trying to achieve an action filter that logs when and action begins and when it end
I am well aware of the .AsActionFilter() method in Autofac 3.0 BUT...
The project that this is using is based in Orchard 1.6 which is known to be compatible with autofac 2.6.xxx. We do not want to go through a potentially lengthy process of upgrading to Autofac 3.0 at this time so the .AsActionFilter() option is not available to us.
The other option is to set the filter (which extends ActionFilterAttribute) as an attribute on our base controller (from which all other inherit btw). The problem is that the filter itself has two dependencies:
A service of our own that holds information on the context
An implementation of an ILoggingService
What I cannot find is a way to inject these into the actual property at the head of the class. Does anyone know a way in which to achieve this either through the [Attribute] line itself of some function of Autofac during registation?
The ActionFilterAttribute:
public class GRMSActionLoggingFilter : ActionFilterAttribute {
private readonly IGRMSCoreServices _grmsCoreServices;
private readonly ILoggingService _loggingService;
public GRMSActionLoggingFilter(IGRMSCoreServices grmsCoreServices, ILoggingService loggingService) {
_grmsCoreServices = grmsCoreServices;
_loggingService = loggingService;
}
public GRMSActionLoggingFilter() { }
public override void OnActionExecuting(ActionExecutingContext actionContext) {...}
public override void OnActionExecuted(ActionExecutedContext actionContext) {...}
}
Assigning the attribute to the base controller:
// This currently compiles but will fail during run time as the IGRMSCoreSerivces and ILoggingService will both be null. Need to property inject these services somehow.
[GRMSActionLoggingFilter]
Anyone have any idea to achieve this?
You cannot (easily) inject runtime values to attributes.
This is how attributes work in C# - you can only pass constant values of certain types. You can read more about it here.
In order to achieve desired functionality in Orchard you need to split your code into two components:
a marker attribute class you put on your action
an action filter class inheriting from FilterProvider and implementing IActionFilter
The way it works is that you put an attribute on some action and then use the action filter to check existence of that attribute (using filterContext.ActionDescriptor.GetCustomAttributes(...)). If an attribute exists, do your stuff.
There are lots of examples of this technique in Orchard core. Check eg. the ThemedAttribute and ThemeFilter action filter classes.
I'm trying to implement my custom authorize attribute like:
public class MyCustomAuth : AuthorizeAttribute
{
private readonly IUserService _userService;
public MyCustomAuth(IUserService userService)
{
_userService= userService;
}
... continued
}
I am using Castle Windsor for automatically resolve the dependency.
When I try to use it as an attribute of an action method obviously I am asked to pass the parameter or I need to have a parameter-less constructor that should resolve in some way it's dependency.
I tried to inject the dependency with a property but Windsor is not injecting it.
The only option I see now would be to instantiate manually the concrete object dependency loosing the benefit of Windsor.
How would you solve this problem?
You cannot use DI with attributes - they're metadata;
public class MyCustomAuth : AuthorizeAttribute
{
public void OnAuthorization(...)
{
IUserService userService = ServiceLocator.Current.GetInstance<IUserService>();
}
}
Learn about Windsor/ServiceLocator here.
See similar question here.
You can use a custom ControllerActionInvoker and inject property dependencies (you can't do constructor injection because the framework handles instantiation of attributes). You can see a blog post I just did on this technique.
You did not supply any castle code or configuration examples. Therefore, I am assuming you are new to castle and unfimilar with the registration process.
First of all, any object you want to act upon must come from Castle Windsor via a registered type. With that said, you are going down the wrong path by trying to use castle windsor with attributes - because attributes are not referenced in code, but instead are reflected upon. Therefore, there is not a place for IoC (Castle Windsor in this case) to create the object.
I say this, because what you are trying to accomplish has already been done via different means. First of all, put your dependency injection on your controllers.
public class PostController
{
private IUserService _userService;
public PostController (IUserService userService)
{
_userService = userService;
}
// other logic
}
For Castle to work, you have register all types. So, you have to register IUserService, and what services implement that interface, within Castle Windsor. You can do this via a manual process in your global.asax with container.AddComponentWithLifeStyle; or the more preferred method is to use a configuration file.
Using a configuration file, your IUserService would look something like this:
<?xml version="1.0" encoding="utf-8" ?>
<castle>
<components>
<!--lifestyle="singleton|thread|transient|pooled|webrequest|custom"-->
<component
id="UserService"
service="MyMvcProject.IUserService, MyMvcProject"
type="MyMvcProject.UserService, MyMvcProject"
lifestyle="transient">
</component>
</components>
</castle>
MyMvcProject is the name of your project and make sure to use the exact namespace and fully qualified name of the interface, and type. Please give code samples of your actual namespaces, else we cannot help you any further.
Before that will work, you will need to modify your app.config or web.config to register the searchGroup for Castle Windsor:
<configSections>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
</configSections>
<castle configSource="castle.config"/>
Now that you are all registered and setup, it is time to tell your MVC application to "Use Castle Windsor to create each instance of my Controllers." Doing this means that Castle Windsor, being an Inversion-of-Control (aka IoC) container, will inspect the dependencies of your controller and see that it depends on IUserService and implement an instance of UserService. Castle will look into its configuration of registered types and see that you have registered a service for IUserService. And, it will see in your configuration file that you want to implement the concrete class of UserService that implements IUserService. So, the IoC container will return UserService when a dependency on IUserService is requested.
But before that can happen, you have to tell your MVC application to use your configuired IoC container. You do this by registering a new ControllerFactory. To do that, see my answer over at this question:
Why is Castle Windsor trying to resolve my 'Content' and 'Scripts' folder as a controller?
And notice the global.asax part of how to register that code. It works quite well!
Now, when all of that is said and done, you want to authorize a user. Use the normal [Authorize] that implements Forms Authentication, and use your _userService to grab any user details of the signed in user.