How to use Autofac in seperate areas in mvc3? - asp.net-mvc-3

I am now working on source code regarding ecommerce. In this source code , brnmall.web is the web project, its admin platform is in library brnmall.web.storeadmin which is registered in web project as area.
below is the brnmall.web:
below is the brnmall.web.storeadmin, registered as area in brnmall.web:
I want to use autofac in brnmall.web.storeadmin, so I add another global.asax in it, in the application_start method, I register all the controllers and components that I need.
but when I use the code below to trigger data
public ActionResult Index()
{
var serviceTypeRepo = unitOfWork.Repository<BrnMall.DAL.Access.cha_servicetype>();
var result = serviceTypeRepo.Get(x => x.serviceid == 1);
ViewBag.result = result;
return View();
}
exception throw to me: "An error occurred when trying to create a controller of type 'BrnMall.Web.Charging.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor."
Anyone have the same scenario?

Is BrnMall.Web.StoreAdmin a seperate Web Application Project or an assembly project that is referenced by BrnMall.Web?
If StoreAdmin is just an Assembly referenced by BrnMall.Web and not a runnable Web Application on its own, then I believe you can remove the Seperate registrations and the global.asax in the StoreAdmin project, but I would replace these registrations with an AutofacModule registration class like below which will then register all your Controllers in that Assembly.
Then to wire it all up, you just need to have BrnMall.Web Autofac registration register your new module which will register Controllers in that assembly and any other components you decide to register there.
eg.
In your BrnMall.Web project....
public class Global : HttpApplication
{
private void Application_Start(object sender, EventArgs e)
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly()); //Register controllers in the Executing Assembly
builder.RegisterModule<BrnMall.Web.StoreAdmin.AutofacModule>(); //Register the registrations in the StoreAdmin Autofac Module below.
//Register any other components
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
And in your BrnMall.Web.StoreAdmin ...
using Autofac;
public class AutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterControllers(ThisAssembly); //This will register any Controllers that are in this assembly
//Register any other components that relate to this particular Project
}
}
The benefit to registering Autofac Modules and referencing them is that you can specify in each project the registrations that belong to just that assembly which keeps the code a lot neater and all your registrations a lot neater.
I hope this helps?

Related

Unity interface mapping exception in web api

I am getting this exception while debugging code:
Resolution of the dependency failed, type = "Aqueduct.Interfaces.IMasterDataClient", name = "MDS".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type,
Aqueduct.Interfaces.IMasterDataClient, is an interface and cannot be constructed. Are you missing a type mapping?
At the time of the exception, the container code was:
Resolving Aqueduct.Interfaces.IMasterDataClient,MDS
Unity.config:
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
IUnityContainer myContainer = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
myContainer.RegisterType<IMasterDataClient, MasterDataClient>("MDS");
myContainer.RegisterType<ILinksManager, LinksManager>("LDS");
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
Web Api controller:
using (var container = new UnityContainer())
{
container.Resolve<IMasterDataClient>("MDS");
container.Resolve<ILinksManager>("LDS");
}
MasterDataClient Interface Implementing class:
public class MasterDataClient : HalClient, IMasterDataClient, IHalClient, ICrestaClient
{
public MasterDataClient(IApiClient apiClient, IUriDispenser dispenser);
}
You have three problems here.
Problem 1. You're creating a new container:
using (var container = new UnityContainer())
{
container.Resolve<IMasterDataClient>("MDS");
container.Resolve<ILinksManager>("LDS");
}
This container will be empty and have 0 registrations. It's not the same container as you made your registrations to. There's a couple of ways to solve it:
Problem 1 - Solution 1: Don't inject the container. Inject the dependencies.
Instead of using the container you should inject your dependencies directly to your controller:
public class MyApiController : ApiController
{
IMasterDataClient _masterDataClient;
ILinksManager _linksManager
public MyApiController(IMasterDataClient masterDataClient, ILinksManager linksManager)
{
_masterDataClient = masterDataClient;
_linksManagerlinksManager;
}
}
This way you can avoid the service locator-pattern and your dependency to the container itself. If you're using named registrations you may need to use the Dependency-attribute.
With Unity how do I inject a named dependency into a constructor?
Problem 1 - Solution 2: Inject your container instead of creating a new one.
If you really need your controller for some reason, then you should try to inject it instead. This way you will get the same container as you used for your registrations.
public class MyApiController : ApiController
{
IUnityContainer _container;
public MyApiController(IUnityContainer container)
{
_container = container;
}
}
Problem 1 - Solution 3: Keep an static reference to your container.
As a last resort you can keep your container as a static instance.
public static class IocContainer
{
private static readonly Lazy<IUnityContainer> Container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
return container;
});
public static IUnityContainer Instance
{
get { return Container.Value; }
}
}
And in your registrations:
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = IocContainer.Instance;
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
myContainer.RegisterType<IMasterDataClient, MasterDataClient>("MDS");
myContainer.RegisterType<ILinksManager, LinksManager>("LDS");
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
Usage:
IocContainer.Instance.Resolve<IMasterDataClient>("MDS");
Problem 2. You don't seem to register the dependencies for MasterDataClient.
It has dependencies for IApiClient and IUriDispenser. They need to be registered as well.
Problem 3. You assign your dependency resolver to the wrong container
You currently create two containers - myContainer and container. You make your registrations to one container, and then use another one as DependencyResolver. You can solve it by removing myContainer and only use container. Otherwise you will not be able to use your registrations in Web Api.
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
container.RegisterType<IMasterDataClient, MasterDataClient>("MDS");
container.RegisterType<ILinksManager, LinksManager>("LDS");
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
Update:
I don't know implementing classes for IApiClient and IUriDispenser as
it is third party dll so how can I register it
Unity needs to know which implementation to use when you resolve an interface. So somehow you need to tell Unity what implementation to use. There's an excellent answer from Mark Seemann in the question below:
Unity IoC for resolving assemblies dynamically
It scans the assembly for implementations of your interface and then registers them/it.
Alternatively you can use registration by convention, which enables you to do several registrations at once:
container.RegisterTypes(
AllClasses.FromLoadedAssemblies(),
WithMapping.MatchingInterface,
WithName.Default,
WithLifetime.ContainerControlled);
Note that this will register all implementations, including your own.
If you just want the third party implementations you should be able do do something like this:
// Get the assemblies where IApiClient exists.
IEnumerable<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(x => x.GetTypes().Contains(typeof (IApiClient)));
// Register all implementations based on convention.
container.RegisterTypes(AllClasses.FromAssemblies(assemblies),
WithMappings.FromMatchingInterface,
WithName.Default,
WithLifetime.ContainerControlled); // Maybe another lifetime manager?
Update 2:
Make sure that the controller has a parameterless public constructor.
The error above can have many causes, most of them are covered in these questions:
Unable to inject DBContext into my Web API 2 Controller with Unity
Make sure that the controller has a parameterless public constructor error
error: Make sure that the controller has a parameterless public constructor webapi
Mostly it's Unity telling you that you're trying to resolve something that you didn't register. Or that you haven't registered a DependencyResolver at all.

Managing AutoFac object creation for UnitOfWork

I am new to architecture, I am in the process of learning and designing an application end to end. I have the below architecture and am using Autofac to manage object creation.
All businessobject contracts have been setup on webapi startup and that is the only startup which can actually startup all my autofac configurations/modules.
I use UnitOfWork/Repository pattern and it resides beyond my business layer, I do not want to refer the UnitOfWork in my WebAPi but i cannot startup UnitOfWork otherwise.
Can someone please give me some inputs on what should be my architecture/design/autofac unitofwork implementation?
In App_start register web project specific dependencies (controllers, etc). Have a static method in BL layer which registers unit of work, repositories, etc. Call this static method in App_start when all the web dependencies are being registered as below:
//App_Start (web project)
var builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
MyProject.BusinessLayer.RegisterDependancies.Register(builder); <-- Register Unit of Work here in static BL method
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterApiControllers(typeof(MvcApplication).Assembly);
builder.RegisterModule<AutofacWebTypesModule>();
builder.RegisterWebApiFilterProvider(config);
builder.RegisterModule(new AutofacModules.AutoMapperModule());
builder.RegisterModule(new AutofacModules.Log4NetModule());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
//Static method in BL
namespace MyProject.BusinessLayer
{
public static class RegisterDependancies
{
public static void Register(ContainerBuilder builder)
{
builder.RegisterType<MyContext>().As<IDataContextAsync>().InstancePerLifetimeScope();
builder.RegisterType<UnitOfWork>().As<IUnitOfWorkAsync>().InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepositoryAsync<>)).InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(typeof(BusinessService).Assembly).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();
}
}
}

MVC 3 Forms authentication with IOC container

I have a problem implementing forms authentication with an IOC container in my ASP.NET MVC 3 project. We have stored our user information in the database and has a lot of custom properties.
I have an interface of my user definition registrated to the IOC container for development purposes. This interface is given to each controller so the controllers has current user information.
This al works fine until i remove the dummy user registration in the Application_Start
I receive this error:
The current type, ...CurrentUserInformation.IUserInformation, is an interface and cannot be constructed. Are you missing a type mapping?
I don't want to work with a dummy user object because I think this is not the best practice.
Can sombody help me or is there a better way to do this custom authentication?
edit added some code
BaseController
public class BaseController : Controller
{
private readonly IUserInformation _userInformation;
public BaseController(IUserInformation userInformation)
{
_userInformation = userInformation
}
}
Bootstrapper Initialize called from Application_Start
public static void Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
//register all services en repositories
//here i put my dummy user wich i want to remove
container.RegisterInstance<IUserInformation>(
new UserInformation
{
UserId = 1,
...
});
return container;
}
You can use InjectionFactory:
container.RegisterType<IUserInformation, UserInformation>(
// User information is destroyed when the request ends.
// You could use an HttpSessionLifetimeManager as well, if it fits your needs
new HttpRequestLifetimeManager(),
new InjectionFactory(container => {
UserInformation userInfo = // TODO: build your userInformation from custom authentication
return userInfo;
}));

Plugin Architecture with ninject – load class and controller instances from plugin assembly to main MVC project

I use this tutorial to create Plugin Architecture in my solution and I also use ninject for the first time:
http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=358360&av=526320&msg=4308834#xx4308834xx
Now in MVC application while user is in the process of checkout I get the payment method he selects and need to retrieve the plugin for the selected payment method. I have succeeded in retrieving plugin controller this way, though I have no idea whether it is safe or acceptable practice:
Type type = Type.GetType(paymentMethod.PaymentMethodPluginType);
//get plugin controller
var paymentController = ServiceLocator.Current.GetInstance(type) as BasePaymentController;
//get validations from plugin
var warnings = paymentController.ValidatePaymentForm(form);
//get payment info from plugin
var paymentInfo = paymentController.GetPaymentInfo(form);
//…
I also need to access a plugin class for processing the payment.
I have an interface IPaymentMethod
public partial interface IPaymentMethod
{
void PostProcessPayment (PostProcessPaymentRequest postprocessPaymentRequest);
}
And plugin PaymentProcessor like this
public class PluginPaymentProcessor :IPaymentMethod
{
public void PostProcessPayment (PostProcessPaymentRequest postprocessPaymentRequest)
{
///
}
Now in MVC project I try to access PostProcessPayment method this way
IPaymentMethod pluginpaymentmethod = ServiceLocator.Current.GetInstance<IPaymentMethod>(paymentMethod.PaymentProcessor);
here paymentMethod.PaymentProcessor is “MyApp.Plugins.MyPlugin.PluginPaymentProcessor, MyApp.Plugins.MyPlugin,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”
And want to use pluginpaymentmethod like i do in controller example
pluginpaymentmethod.PostProcessPayment(postProcessPaymentRequest);
but it throws error that resource is not found and pluginpaymentmethod is not loaded. How can I fix it or can you suggest any tutorial with similar implementations? Thank you.
assuming you have a concrete class called MyPlugin which has the IPaymentMethod interface, then your ninject bindings should look a bit like:
private static void RegisterServices(IKernel kernel){
kernel.Bind<IPaymentMethod>().To<MyPlugin>().InRequestScope();
}
check that this is in place in your NinjectWebCommon.cs class under the App_Start folder. A trickier scenario might be that IPaymentMethod has to be registered in the same way that the Ninject IKernel is bound:
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
that would potentially be a trickier issue to work out.

Getting SNAP(AOP), NInject and ASP.Net MVC 3 working together

Has anyone got the SNAP AOP framework working with MVC 3 and Ninject.
The samples given when adding Snap using NuGet to an MVC 3 project don't specifcally work well with a previously added NInject package. I have tried to get it working based on the normal NInject approach but just cannot get it to actually intercept!
Can anyone show how to do this in code please?
I figured it out with the latest version of Ninject through NuGet which now adds a class call NinjectMVC3 in a new AppStart folder in the MVC3 application.
The code I used is as folows:
In the automatically created NinjectMVC3.cs CreateKernel() method:-
private static IKernel CreateKernel()
{
// Wire it up with AOP
NinjectAopConfiguration.NinjectAopConfigure();
//var kernel = new StandardKernel(); // Removed
RegisterServices(NinjectAopConfiguration._container.Kernel);
return NinjectAopConfiguration._container.Kernel;
}
I also wired up Ninject for the various injection targets in RegisterServices() method.
Next I took the sample code generated by NuGet when adding SNAP.Ninject to the MVC 3 application, renamed it NinjectAOP.cs and made it look like this:
public static class NinjectAopConfiguration
{
public readonly static NinjectAspectContainer _container;
static NinjectAopConfiguration()
{
_container = new NinjectAspectContainer();
}
public static void NinjectAopConfigure()
{
SnapConfiguration.For(_container).Configure(c =>
{
c.IncludeNamespace("MyNamespace.Model.*");
c.Bind<ExceptionLoggingInterceptor>().To<ExceptionLoggingAttribute>();
});
}
}
I also needed to do an assembly binding redirect for Ninject as follows because there is an assembly version conflict somewhere for Ninject:
I hope this helps someone.
I invite anyone to have a look and see if they can improve this please.

Resources