I've been using the Ninject.Web extension to inject business objects, repositories, Entity Framework context etc into my application. This works very well using the [Inject] attribute which can be applied within a webform that inherits from PageBase. I am now running into a snag as I am trying to write a custom membership provider that needs injection done inside of it but of course this provider is not instantiated from within a webform. Forms Authentication will instantiate the object when it needs it. I am unsure how to about doing this without having access to the [Inject] attribute. I understand that there is an application level kernel somewhere, but I have no idea how to tap into it. Any suggestions would be greatly appreciated.
You don't have to use the service locator pattern, just inject into properties of your custom membership provider in Application_Start. Assuming you've registed the providers properly you can do this with something like:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
// Inject account repository into our custom membership & role providers.
_kernel.Inject(Membership.Provider);
// Register the Object Id binder.
ModelBinders.Binders.Add(typeof(ObjectId), new ObjectIdModelBinder());
}
I've written up a more in depth explanation here:
http://www.danharman.net/2011/06/23/asp-net-mvc-3-custom-membership-provider-with-repository-injection/
You do a IKernel.Inject on the the instance. Have a look at the source for the Application class in the extension project you're using.
In the case of V2, it's in a KernelContainer. So you need to do a:
KernelContainer.Inject( this )
where this is the non-page, non application class of which you speak.
You'll need to make sure this only happens once - be careful doing this in Global, which may get instantiated multiple times.
Also, your Application / Global class needs to derive from NinjectHttpAppplication, but I'm sure you've that covered.
you may need to use the Service Locator pattern, since you have no control over the creation of the membership provider.
Related
I'm just learning asp.net mvc and I'm trying to figure out how to move my controllers into a separate project. Typically when I have designed asp.net web apps before, I created one project for my models, another for my logic, and then there was the web.
Now that I'm learning asp.net mvc I was hoping to follow a similar pattern and put the models and controllers each into their own separate projects, and just leave the views/scripts/css in the web. The models part was easy, but what I don't understand is how to make my controllers in a separate project be "found". Also, I would like to know if this is advisable. Thanks!
First of all, it is certainly a good idea to put your model into a separate project. As you've discovered, this is trivial.
Regarding Controllers and Views, I don't see any obvious advantage to separating them for most basic projects, although you may have a particular need to do so in a particular application.
If you do choose to do this, then you will need to tell the framework how to find your controllers. The basic way to do this is by supplying your own ControllerFactory. You can take a look at the source code for the DefaultControllerFactory to get an idea for how this is done. Subtyping this class and overriding the GetControllerType(string controllerName) method may be enough to accomplish what you're asking.
Once you've created your own custom ControllerFactory, you add the following line to Application_Start in global.asax to tell the framework where to find it:
ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
Update: Read this post and the posts it links to for more info. See also Phil Haack's comment on that post about:
ControllerBuilder.Current.DefaultNamespaces.Add(
"ExternalAssembly.Controllers");
...which is not a complete solution, but possibly good enough for simple cases.
While it is reasonable to create your own ControllerFactory, I found it more convenient to define all my Controllers in each project, but derive them from Controllers in my Shared project:
namespace MyProject1.Controllers
{
public class MyController : MySharedProject.Controllers.MyController
{
// nothing much to do here...
}
}
namespace MySharedProject.Controllers
{
public abstract class MyController : System.Web.Mvc.Controller
{
// all (or most) of my controller logic here...
}
}
This has the added benefit that you have a place to put your Controller logic that differs from project to project. Also, it is easier for other developers to quickly find your Controller logic because the Controllers exist in the standard place.
Regarding whether this is advisable, I think it absolutely is. I've created some common Account Management logic that I want to share between projects that otherwise have very different business logic. So I'm sharing my Account and Admin Controllers, but the other Controllers are specific to their respective projects.
Add the Class Library for your mvc project.
In the class add the following code(For u'r Controller Code)
namespace ContactController
{
public class ContactController : Controller
{
public ActionResult Call()
{
ViewBag.Title = "Inside MyFirst Controller.";
return View();
}
}
}
On the mvc project view folder add the folder for Contact and create a Call.cshtml file.
Add the class library project reference into your main MVC project.
Finally to refer contact controller namespace into Route Config.
My problem solved after I updated System.Web.Mvc NuGet reference so MvcWebsite and Class Library use same System.Web.Mvc version
No need to add default namespaces
The simplest form of separation I use is to retain the Views "as is" in the original MVC project but remove the Controllers. Then in a new ClassLibrary project add the Controller classes and ensure they inherit from Controller.
The MVC routing engine will automatically route to the Controllers in the ClassLibrary and the Controllers will automatically construct the Views from the original MVC project, provided you have your references and usings correctly in place.
I am using this architecture to implement an Html Reports module that can be compiled and deployed separately from the main solution. At last I am free from SSRS!
When using Unity 2.0 for dependency injection within a web application, it appears that user controls, pages, etc will all need make explicit calls to retrieve the container and "fetch" the dependencies … so using the annotations like [dependency] won't offer any value. This is likely since the location of the container (application context, http context cache, etc.) is unknown in the web configuration.
Since Unity itself provides method interception, isn't there a way to "tell" unity how to fetch the container correctly when you build your own web application? Rather than having to create base classes for page, etc.?
The problem is that the WebForms Pages and Controls are not set up to allow for construction by dependency injection, so Unity never gets invoked at all unless the class invokes Unity itself. I've found the best pattern in these cases is to invoke the DI framework in the constructor via a Service Locator and then use annotations to mark dependency properties. Something like this:
public MyPage()
{
// Injector is a wrapper class so you can change the underlying DI framework
// later if necessary.
Injector.Inject(this);
}
[Dependency]
public SomeService MyService {get;set;}
Whenever I try to actually unit test a presenter and a mocked view, I end up running into too many database dependencies
public EditAccount(IAccountEditPage _view, ISession _session, IResponse _response)
{
}
public void view_SaveUser()
{
//Class that takes the view's data and persists it to DB
}
Obviously I can't write unit tests for this presenter because I have a concretion of using my model class that has a strong database dependency.
How am I supposed to removed the dependency on the database without constructor injecting every class that touches the database in my presenter? I don't want to do this every time in every view I have.
I'm using moq, if it helps.
Edit : Also I should mention that the code in "view_SaveUser" is very lean and isn't direct database access or anything like that. It's usually only a few lines. I'm not overstepping the scope of the presenter, AFAIK.
If you don't want to inject the instances on the constructor another option you have is using a setter injection using a IoC framework as Spring.Net or Castle Windsor to inject the dependencies.
Doing this, you would only need to specify on the framework configuration which classes are used for real code and for test project, dependencies would be automatically injected and you would avoid having to use the contructor.
I have a property on my Global.asax.cs class that I need to access from a business class, i.e. using HttpContext.Current.
How do I do this?
Global.asax.cs (in a web project)
public partial class Global : System.Web.HttpApplication
{
public static ProxyGenerator Generator = new ProxyGenerator();
Business class (in a separate business project)
var generator = ((Sei.Osp.Web.Global)HttpContext.Current.ApplicationInstance)
This obviously doesn't work and I don't want to reference the whole web project in the business project as it will create a circular reference (the business project is already referenced in the web project)
UPDATE:
To clarify - the property I'm creating holds an instance of the Castle Dynamic Proxy Generator class. I've read that you shouldn't just create this all over the place.
So I thought I'd create it in my Global.asax.cs and then just use that instance wherever I need to create a proxy class (I'm using it to do AOP)
Is there a better way of doing this?
A better technique would be to create a class (possibly static) with the public static property you want, then reference it from both Global.asax.cs and your business class.
The class could be in your business project, or in a separate project referenced by both your business project and the web project.
Your business classes need to be independent of your web site. You need to reevaluate your reasons for doing it this way. Either the business class doesn't really need access to the property, or the property doesn't need to be in global.asax.
I have a class which inherits from the System.Web.UI.Page class, like mysystem.
When I try to create an instance of mysystem in a winform appplication it throws an HttpException:
Session state can only be used when
enableSessionState is set to true,
either in a configuration file or in
the Page directive. Please also make
sure that
System.Web.SessionStateModule or a
custom session state module is
included in the
<configuration>\<system.web>\<httpModules>
section in the application
configuration.
I then googled this problem and try to enable the session state, but all are not affected.
So, can anybody tell me how to solve this case?
Any class that inherits from System.Web.UI.Page will attempt to utilise parts of the asp.net runtime when it's instantiated, so when it's used in a winforms application, it just won't work.
If there are methods that you need inside this class from another DLL, I'd suggest refactoring them into a separate class as:
If you want to use them in a winforms app, they're almost certainly not specific to the page so should be shared anyway
There's no good reason to try and use the asp.net runtime (other than, perhaps, caching) inside a winforms application