I recently came across this article titled:
Linq to Sql and ASP.NET MVC – DataContext Per Request
at this link:
http://www.jeremyskinner.co.uk/2010/01/31/linq-to-sql-and-asp-net-mvc-datacontext-per-request/
I would like to set this up using ninject rather than structuremap preferably using the new mvc 3 dependency resolver as I'm using mvc 3 rtm.
The relevant part of the article is this:
Firstly, you’ll need to configure StructureMap by calling ObjectFactory.Configure inside your Global.asax passing in a custom Registry instance:
protected void Application_Start() {
RegisterRoutes(RouteTable.Routes);
ObjectFactory.Configure(cfg => {
cfg.AddRegistry(new MyRegistry());
});
}
The code for MyRegistry looks like this:
public class MyRegistry : Registry {
public MyRegistry() {
For<BlogDataContext>()
.HttpContextScoped()
.Use(c => new BlogDataContext());
Scan(scan => {
scan.AddAllTypesOf<Controller>();
});
}
}
Here I’m telling StructureMap to create one instance of my BlogDataContext per HTTP Request as well as registering each Controller instance with the container.
Next, we need to tell MVC to use StructureMap to instantiate our controllers. This can be done by creating a custom ControllerFactory:
public class StructureMapControllerFactory : DefaultControllerFactory {
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
return (IController) ObjectFactory.GetInstance(controllerType);
}
}
We can then replace the DefaultControllerFactory with the StructureMapControllerFactory in our Application_Start:
protected void Application_Start() {
RegisterRoutes(RouteTable.Routes);
ObjectFactory.Configure(cfg => {
cfg.AddRegistry(new MyRegistry());
});
ControllerBuilder.Current.SetControllerFactory(
new StructureMapControllerFactory());
}
I would like to do the same thing with ninject 2.0 rather than structure map. I'm building an mvc 3 site with ninject mvc3. I downloaded the ninject mvc 3 package from nuget and I have this file in my solution which handles wiring up ninject.
AppStart_NinjectMVC3.cs
I do not want to use structurmap and I know the same setup can be done with ninject, but I'm unsure how to wire it up.
Thank you.
I'd rather use the official mvc3 extension from the ninject project found at https://github.com/ninject/ninject.web.mvc. It comes with a full example application showing how to wire up an mvc3 application.
Related
I have the following :
a class library with connection classes such as connection, command, parameter
a DAL with entities, mapper, interface, services as well as a static class that holds hard coded connectionString and InvariantName.
an Asp.Net Core project
References :
DAL has a reference to the class library to make use of its connection class to which it provides connectionString and InvariantName thanks to its static class etc..
Asp.Net has a reference to the DAL.
What I want :
I now want to use the User Secrets to store hard coded sensitive data connections and get rid off the static class.
I know I can use the the Asp.Net Core startup.cs to read the settings from Configuration and make use of binding to store them into a class and use DI.
My guess :
DI seems "easy" when used inside an Asp controller. But I need the settings values (connectionString and InvariantName) outside the Asp.Net Core to be injected into a constructor of a class somewhere in my DAL.
I guess I would then need to have to reference the Asp.Net Core project to my DAL. But then I would end up with a circular reference (DAL to Asp.Net Core and the opposite).
So what's the solution?
Have an intermediate library class into which I would retreive the settings values from Asp.Net Core and then pass them to my DAL (to prevent circular reference)?
Manually recreate the "Configuration process" inside the DAL and get settings there directly
Or something else that I don't know?
Ps : I am new in development and only have a few projects'experience in Asp.Net Framework so far..and it's my first Asp.Net Core project
I know I can use the the Asp.Net Core startup.cs to read the settings from Configuration and make use of binding to store them into a class and use DI
You already answered your own question with this. This is the correct and recommended behavior to setup DI for 3rd party libs and configurations. If you want to avoid clutter in Startup class, create an extension method:
namespace Microsoft.Extensions.DependencyInjetion
{
public static MyLibraryCollectionExtensions
{
public static IServiceCollection AddMyLibrary(this IServiceCollection services)
{
services.AddDbContext<MyDbContext>(...);
}
}
}
to register your classes. Alternatively, extend the method to accept a parameter delegate to configure it
namespace Microsoft.Extensions.DependencyInjetion
{
public static MyLibraryCollectionExtensions
{
public static IServiceCollection AddMyLibrary(this IServiceCollection services, Action<MyOptions> setup)
{
var defaultOptions = ... // i.e. new MyOptions();
// pass default options to be modified by the delegate
setup?.Invoke(defaultOptions);
// your registrations
services.AddDbContext<MyDbContext>(...);
}
}
}
And all the user has to do in your library is add
services.AddMyLibrary();
// or with setup
services.AddMyLibrary(config =>
{
config.MyConnectionString = Configuration.GetConnectionString("MyContext");
});
and store the connection string in the appsettings.json.
{
"ConnectionStrings":
{
"MyContext" : "MyConnectionString here"
}
}
I finally used the ConfigurationBuilder to get values from the appsettings.json file.
It's probably not the right way to do it but it is working with my DAL and Connection dlls.
In case it helps anyone else :
I would like to reuse a library class that I made for some projects in Asp .Net Framework within an Asp .Net Core project on which I am now working.
For that project I have to use a MySQL database so I added the MySqlConnector NuGet package to my library class.
As the registered .NET Data Providers are not automatically added to the Global Assembly Cache I must register it manually thanks the call of that method DbProviderFactories.RegisterFactory("MySqlConnector", MySqlClientFactory.Instance) during application startup as mentionned here.
It's my first .Net core project so I don't know if that's how I should do it but I called that method in the Startup.cs file like this :
It is working but I am wondering if it's the right way to do it. Would you advise me another proper way to do it?
Thanks
There is nothing fundamentally wrong with your approach, IMO.
One problem I see is the task you're trying to run takes too long, in which case you're better off spawning a task.
The other is reusability, your code is coupled together. You could solve that by wrapping it in a class and injecting it into a middleware component by interface, and then calling a method. For example:
public interface ITask { void Run(); }
class RegisterMySqlTask : ITask { public void Run() { DbProviderFactories.RegisterFactory("MySqlConnector", MySqlClientFactory.Instance); } }
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ITask, RegisterMySqlTask>();
//rest goes here
}
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
context.RequestServices.GetRequiredService<ITask>().Run();
await next(context);
});
//rest goes here
}
Note, however, that this may be overcomplicating things. As I said, I believe that you are not doing anything wrong.
I have created and MVC 4 web application and decided to use web api in this app.
I'm using ninject dependency resolver for MVC web app. and now I want to use this ninject dependency resolver for web api.
but the problem raise here mvc IDependencyResolver namespace is: using System.Web.Mvc
and web api IDependencyResolver is using System.Web.Http.Dependencies
so how can I solve this issue?
finally I want something like this:
// Use the container and the NinjectDependencyResolver as
// application's resolver
var resolver = new NinjectDependencyResolver(container);
//Register Resolver for MVC
DependencyResolver.SetResolver(resolver);
//Register Resolver for Web Api
GlobalConfiguration.Configuration.DependencyResolver = resolver;
There is a way to share same container between MVC and ASP.NET Web API.
You just need to implement both interfaces.
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver, System.Web.Mvc.IDependencyResolver
{
private readonly IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(this.kernel.BeginBlock());
}
}
Check this article for solution:
Simple Way to share Dependency Resolvers between MVC and Web API
There is a NuGet package that does this. Add the NInject, NInject.Web.Common, NInject.MVCx and WebApiContrib.IoC.Ninject NuGet packages to your project. A NInjectWebCommon class should have been created in the App_Start folder. Add your binding for your dependencies to the RegisterServices method. In the CreateKernel method after the RegisterServices(kernel) call, add the following line:
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
This will let you create the Ninject dependency resolver without having to create your own override class. Easy, right?
My current setup is using Ninject for simple IoC, everything goes fine, but I'm not able to resolve one of the classes I need inside my AuthorizeAttribute. I need to access a class that does ClaimsVerification:
Here's my code:
IoC Config:
var kernel = new StandardKernel(); // Ninject IoC
// These registrations are "per instance request".
// See http://blog.bobcravens.com/2010/03/ninject-life-cycle-management-or-scoping/
kernel.Bind<RepositoryFactories>().To<RepositoryFactories>()
.InSingletonScope();
kernel.Bind<IRepositoryProvider>().To<RepositoryProvider>();
kernel.Bind<ISmartDocumentorUow>().To<SmartDocumentorUow>();
kernel.Bind<IClaimsVerification>().To<ClaimsVerification>();
// kernel
//kernel.BindFilter<MyAuthorizeAttribute>(FilterScope.Controller, 0).WhenControllerHas<RequireRolesAttribute>();
// Tell WebApi how to use our Ninject IoC
config.DependencyResolver = new NinjectDependencyResolver(kernel);
MyAuthorizeAttribute:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
[Inject]
IClaimsVerification clamisverify { get; set; }
public MyAuthorizeAttribute()
{
//var x = System.Web.Mvc.DependencyResolver.Current.(typeof(IClaimsVerification));
}
Yap, sorry, the problem was injecting the iClaimsverification that isn't working in web api..
I tryed with the public property and still it didn't work.
the bindfilter is commented out, because it doesn't exist in the core NInject api (dll), it does exists in the MVC dll of ninject but it works for Action filters in the web mvc, and not in the api mvc for what i can tell..
i do solved the issue like this, though i don't like a lot of this fix:
private IClaimsVerification verifier
{
get
{
return (GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IClaimsVerification)) as IClaimsVerification);
}
}
The property you have marked with Inject is private - you need to initialize Ninject with a custom configuration to opt into what would be a much less efficient process
(You didnt state the problem in your question. I see you were trying BindFilter, but it's commented out (why?) - this is the correct approach. I recommend reading the Ninject.MVC3 wiki article on BindFilter for an example)
I have this setup:
public static void Initialize(ISessionFactory factory)
{
var container = new Container();
InitializeContainer(container, factory);
container.RegisterMvcControllers(
Assembly.GetExecutingAssembly());
container.RegisterMvcAttributeFilterProvider();
container.Verify();
DependencyResolver.SetResolver(
new SimpleInjectorDependencyResolver(container));
}
private static void InitializeContainer(
Container container, ISessionFactory factory)
{
container.RegisterPerWebRequest<ISession>(
() => factory.OpenSession(), true);
}
The Initialize method is called in Application_Start:
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
SimpleInjectorInitializer.Initialize(
new NHibernateHelper(
Assembly.GetCallingAssembly(),
this.Server.MapPath("/"))
.SessionFactory);
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
But when i try to call the controller action I get an ArgumentException:
Type 'PositionReportApi.Controllers.PositionsController' does not have
a default constructor
Stack trace:
at System.Linq.Expressions.Expression.New(Type type) at
System.Web.Http.Internal.TypeActivator.Create[TBase](Type
instanceType) at
System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage
request, HttpControllerDescriptor controllerDescriptor, Type
controllerType)
I can't register an ISession.
How do i register an ISession that is created by a factory?
From the stack trace I can see that you are using the new .NET 4.5 ASP.NET Web API and Simple Injector is not in the presented call graph. This probably means that you haven't configured the Simple Injector for use with the new Web API, which is a different registration than what you need for MVC (for some strange reason, and I sincerely hope they fix this in the final release). Since you didn't register a Simple Injector specific System.Web.Http.Dependencies.IDependencyResolver implementation to the Web API's GlobalConfiguration.Configuration.DependencyResolver, you'll get the default behavior, which will only work with default constructors.
Take a look at this Stackoverflow answer Does Simple Injector supports MVC 4 ASP.NET Web API? to see how to configure Simple Injector with the new ASP.NET Web API.
UPDATE
Note that you can get this exception even if you configured the DependencyResolver correctly, but when you didn't register register your Web API Controllers explicitly. This is caused by the way Web API is designed.
Always register your Controllers explicitly.