I am pretty new to Unity & IoC in general & as usual, I have quickly got myself into a bind...
I have created an Authorization Filter Attribute for the ASP.NET Web API Beta. I now need to inject my Authorizer into the Attribute however since this is an attribute I cannot simply do this public TestAuthAttribute(IAuthorizer Authorizer) in my constructor.
So I then decided to create a public property decorated with the [Dependency] attribute for property injection however it does not get resolved.
Here is the code:
public class TestAuthAttribute : AuthorizationFilterAttribute
{
[Dependency]
public IAuthorizer Authorizer { get; set; }
public TestAuthAttribute() {
...
}
private bool authorizeCore(HttpRequestMessage request)
{
if (Authorizer == null)
throw Error.ArgumentNull("Null Authorizer"); // <<<<< this is null
}
When the controller is decorated with the [TestAuth] the Attribute is triggered but the Authorizer is not resolved, it is null)
I have placed the following code in my controller & Authorizer does get resolved...
[Dependency]
public IAuthorizer Authorizer { get; set; }
Why is this dependency not resolved in my AuthorizationFilterAttribute & how would you go about Injecting the Authorizer into the AuthorizationFilterAttribute?
Full disclosure: I have not used Turbine.
Having said that, I think it might solve your problem for you or at least show you how to solve it.
They have a Unity Nuget package here: http://nuget.org/packages/MvcTurbine.Unity
And you can find more detail on their codeplex site here: http://mvcturbine.codeplex.com/
Hope that helps.
I use Ninject for similar purpose. I do have a reference to Ninject.Web.WebAPI which works perfectly.
However, this does not seem working with MVC4 RC.
Related
My theme has some sort of breadcrumb. The controller is always the category. To avoid repeat myself, I want to set it in the constructor of the controller for all actions like this:
class MyController:Controller{
public MyController() {
ViewBag.BreadcrumbCategory = "MyCategory";
}
}
When I access ViewBag.BreadcrumbCategory in the layout-view, its null. In a Action it works:
class MyController:Controller{
public IActionResult DoSomething() {
ViewBag.BreadcrumbCategory = "MyCategory";
}
}
I'm wondering that setting a ViewBag property is not possible in a constructor? It would be annoying and no good practice to have a function called on every action which do this work. In another question using the constructor was an accepted answear, but as I said this doesn't work, at least for ASP.NET Core.
There is an GitHub issue about it and it's stated that this is by design. The answer you linked is about ASP.NET MVC3, the old legacy ASP.NET stack.
ASP.NET Core is written from scratch and uses different concepts, designed for both portability (multiple platforms) as well as for performance and modern practices like built-in support for Dependency Injection.
The last one makes it impossible to set ViewBag in the constructor, because certain properties of the Constructor base class must be injected via Property Injection as you may have noticed that you don't have to pass these dependencies in your derived controllers.
This means, when the Controller's constructor is called, the properties for HttpContext, ControllerContext etc. are not set. They are only set after the constructor is called and there is a valid instance/reference to this object.
And as pointed in the GitHub issues, it won't be fixed because this is by design.
As you can see here, ViewBag has a dependency on ViewData and ViewData is populated after the controller is initialized. If you call ViewBag.Something = "something", then you it will create a new instance of the DynamicViewData class, which will be replaced by the one after the constructor gets initialized.
As #SLaks pointed out, you can use an action filter which you configure per controller.
The following example assumes that you always derive your controllers from Controller base class.
public class BreadCrumbAttribute : IActionFilter
{
private readonly string _name;
public BreadCrumbAttribute(string name)
{
_name = name;
}
public void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
var controller = context.Controller as Controller;
if (controller != null)
{
controller.ViewBag.BreadcrumbCategory = _name;
}
}
}
Now you should be able to decorate your controller with it.
[BreadCrumb("MyCategory")]
class MyController:Controller
{
}
I have the same issue and solve it overriding the OnActionExecuted method of the controller:
public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
ViewBag.Module = "Production";
}
Here is a better way to do this for .NET Core 3.x, use the ResultFilterAttribute:
Create your own custom filter attribute that inherits from ResultFilterAttribute as shown below:
public class PopulateViewBagAttribute : ResultFilterAttribute
{
public PopulateViewBagAttribute()
{
}
public override void OnResultExecuting(ResultExecutingContext context)
{
// context.HttpContext.Response.Headers.Add(_name, new string[] { _value });
(context.Controller as MyController).SetViewBagItems();
base.OnResultExecuting(context);
}
}
You'll need to implement the method SetViewBagItems to populate your ViewBag
public void SetViewBagItems()
{
ViewBag.Orders = Orders;
}
Then Decorate your Controller class with the new attribute:
[PopulateViewBag]
public class ShippingManifestController : Controller
That's all there is to it! If you are populating ViewBags all over the place from your constructor, then you may consider creating a controller base class with the abstract method SetViewBagItems. Then you only need one ResultFilterAttribute class to do all the work.
I'm using SignalR 0.5.2 and I'm trying to get a DependencyResolver set up using Unity. I've written the simplest code I can. I have a hub that I'm trying to inject into which looks like this:
public class SimpleHub : Hub
{
private readonly ITestService _service;
public SimpleHub(ITestService service)
{
_service = service;
}
public void Update()
{
Clients.callback("Kevin");
}
}
and a DependencyResolver that looks like this:
public class UnityDependencyResolver : DefaultDependencyResolver
{
private readonly IUnityContainer _container;
public UnityDependencyResolver(IUnityContainer container)
{
_container = container;
}
public override object GetService(Type serviceType)
{
if (_container.IsRegistered(serviceType))
{
return _container.Resolve(serviceType);
}
return base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
if (_container.IsRegistered(serviceType))
{
return _container.ResolveAll(serviceType);
}
return base.GetServices(serviceType);
}
}
I register the dependency resolver in Global.asax
protected void Application_Start()
{
IUnityContainer container = new UnityContainer();
InitializeContainer(container);
SignalR.IDependencyResolver resolver = new UnityDependencyResolver(container);
GlobalHost.DependencyResolver = resolver;
RouteTable.Routes.MapHubs();
// more MVC stuff here
}
where InitializeContainer register the ITestService in Unity
The resolver "works" in that it's getting called for all the SignalR types, and if I leave my hub with a default constructor it all gets loaded. However the resolver never gets asked to resolve the ITestService interface.
I've also tried passing the resolver to MapHubs, still no luck. I've also tried property injection using the [Dependency] attribute and that didn't work either.
Do I need to register the resolver with MVC as well? (I have tried that by implementing both IDependecyResolver interfaces but get an exception telling me the resolver doesn't implement IServiceLocator)
So I've sort of fixed this. I wondered if the fact that the Hub was registered with the signalr container and the interface was registered with the Unity container was causing the issue. So I registered the Hub with Unity and then everything works.
This sort of makes sense as there are two containers.
Is this the standard behaviour?
In case someone else is wondering... I found a good SPA example that uses
SignalR 1.0.1
Unity 3
A bunch of other frameworks
The interesting thing is the way he create the container, the dependencies and everything else. Worth checking it out.
i have a MVC controller called MyController with an action called MyAction. For other hand i have a Model called MyModel, and all this classes are in a project called Portal.Website (Asp.net MVC3 Application) that i use as a generic website and that store common functionalities for custom websites that i will add in the future.
For other hand i have another website project with a reference to Portal.Website project called Portal.Website.MyCustomWebsite.
This is the viewmodel MyModel.cs in the generic website part:
namespace Portal.Website
{
public class MyModel
{
[Required(ErrorMessage="The field Name is required.")]
[Display("MyPropertyOriginal")]
public virtual string Name{get;set;}
}
}
This is the controller and action in the generic website part:
namespace Portal.Website
{
public class MyController: Controller
{
[HttpPost]
public ActionResult MyAction(MyModel model)
{
if(Model.IsValid)
....
//My issue: Im getting the error message in english, not the overridden one.
}
}
}
This is the viewmodel that i created in the custom part:
namespace Portal.Website.MyCustomWebsite
{
public class MyModel: MyModel
{
[Required(ErrorMessage="My error message in other language.")]
[Display("MyPropertyOverriden")]
public override string Name{get;set;}
}
}
My problem:
I would like to override the ErrorMessage of the Required attribute. For this reason i created a new Model in my custom project. For other hand i would like to use the Controller/Action (MyController/MyAction) that is already defined in my common part.
Do you know if this is possible? Im only getting the issue with the Required attribute, but with the Display one its working perfect.
Thanks in advance.
Greets.
Jose.
You may want to check out this article that suggests two possible solutions :
http://www.codeproject.com/Articles/130586/Simplified-localization-for-DataAnnotations
I've found it was making more sense to re-create some DataAnnotation classes with my custom logic.
MVC3 comes with better support for I18N (internationalisation) than it's predecessors - you can pass the RequiredAttribute the type of your resource class and the resource key and the error message will be displayed in whichever language is most appropriate:
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "ResourceKey")]
public override string Name { get; set; }
Is it possible to inject values/settings into ASP.NET Pages via autofac's PropertyInjectionModule? I get the impression that default handler behavior is to search for properties and find any types that match services in the container.
eg for a page:
public class MyPage: System.Web.UI.Page {
public IDataProvider DataProvider { get; set; }
public bool SomeSetting {get; set; }
public bool AnotherSetting { get; set; }
public string MySettings { get; set; }
// stuff
}
I thought maybe you could specify properties:
builder.RegisterType<MyPage>()
.WithProperty("SomeSetting", true)
.WithProperty("AnotherSetting", false)
.WithProperty("MySettings", "do-re-mi");
but it doesn't seem to work.
I realise I could setup an IMyPageConfig interface and provide settings that way but these are optional properties that may or may not need to be set.
IoC in ASP.NET Pages is a bit limited - although the module is injecting properties into the page, it can't really use Autofac's regular dependency injection features.
In WebForms the way people typically get around this is to use something like Model-View-Presenter, where the page is just a 'dumb' view and the presenter is where the logic (and proper dependency injection) takes place.
Check out http://webformsmvp.com/ - I think there is an IoC example and Autofac support available there.
OK, so I've been working on this for hours. I've found a couple of posts here, but nothing that actually resolves the problem. So, let me try it again...
I have an MVC2 app using Ninject and a custom membership provider.
If I try and inject the provider using the ctor, I get an error: 'No parameterless constructor defined for this object.'
public class MyMembershipProvider : MembershipProvider
{
IMyRepository _repository;
public MyMembershipProvider(IMyRepository repository)
{
_repository = repository;
}
I've also been playing around with factories and Initialize(), but everything is coming up blanks.
Any thoughts/examples?
The Membership provider model can only instantiate a configured provider when it has a default constructor. You might try this using the Service Locator pattern, instead of using Dependency Injection. Example:
public class MyMembershipProvider : MembershipProvider
{
IMyRepository _repository;
public MyMembershipProvider()
{
// This example uses the Common Service Locator as IoC facade, but
// you can change this to call NInject directly if you wish.
_repository = ServiceLocator.Current.GetInstance<IMyRepository>;
}
This is how I was able to do this:
1) I created a static helper class for Ninject
public static class NinjectHelper
{
public static readonly IKernel Kernel = new StandardKernel(new FooServices());
private class FooServices : NinjectModule
{
public override void Load()
{
Bind<IFooRepository>()
.To<EntityFooRepository>()
.WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings["FooDb"].ConnectionString);
}
}
}
2) Here is my Membership override:
public class FooMembershipProvider : MembershipProvider
{
private IFooRepository _FooRepository;
public FooMembershipProvider()
{
NinjectHelper.Kernel.Inject(this);
}
[Inject]
public IFooRepository Repository
{
set
{
_FooRepository = value;
}
}
...
With this approach it doesn't really matter when the Membership provider is instantiated.
I had the same problem at the exact same spot in the book. It wasn't until later on in the book that I noticed there were two separate web.config files. I initially placed my connectionString key in the wrong web.config file. It wasn't until I placed the connectionString in the correct web.config file that the 'no parameterless constructor' error went away.