How to use dynamic module loading in an onion architecture using MVC4 as frontend - asp.net-mvc-4

I'm trying to wrap my head around dependency injection in the Onion Architecture, I've found this solution which uses a dependency resolution layer around the onion. But there is so much going on that I'm completely lost.
So I setup a project to try it out. I like to start off simple, so a simple log entry on a (MVC) controller method would be a good start.
I'd like to use Dynamic Module Loading (kernel.Load("*.dll");) since it comes recommended from the Ninject wiki.
My solution looks like this: (For now)
Solution
- Core.Services
- Infrastructure.Logging
- DependencyResolution
- UI.MVC (default internet template)
I'd like to follow the guides lines for dependency resolution outlined here.
Ilogger
namespace Core.Services
{
public interface ILogger
{
void Log(string message);
}
}
Logging Implementation
namespace Infrastructure.Logging
{
public class DebugLogger : ILogger
{
public void Log(string message)
{
Debug.WriteLine(message);
}
}
}
Dependency Resolution
namespace DependencyResolution
{
public class TestModule : NinjectModule
{
public override void Load()
{
Bind<ILogger>().To<DebugLogger>();
}
}
}
What I want to accomplish
UI
namespace UI.MVC.Controllers
{
public class HomeController : Controller
{
private readonly ILogger _logger;
public HomeController(ILogger logger)
{
_logger = logger;
}
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
_logger.Log("It works!");
return View();
}
}
}
I need to run kernel.Load("*.dll"); somehow and I need to setup my MVC to use DI. I'm just now sure how since the UI cannot know about the Dependency Resolution layer.

Your DI container should be composed somewhere. This place is called the composition root and is the outermost layer. In your case that would be the ASP.NET MVC application. So saying that it should not know about the DI simply doesn't make sense. The Ninject.MVC3 package comes with a custom dependency resolver implementation that gets plugged into the application and you will get automatic DI in your controllers.

Related

Simplified approach to IOptions<T>

I am trying to get a .NET Framework class library in line with an ASP.NET Core 2.1 application while using builtin DI mechanism. Now, I created a config class and added appropriate section to appsettings.json:
services.Configure<MyConfig>(Configuration.GetSection("MyConfiguration"));
services.AddScoped<MyService>();
In class lib:
public class MyService
{
private readonly MyConfig _config;
public MyService(IOptions<MyConfig> config)
{
_config = config.Value;
}
}
However, in order to build this classlib I have to add Microsoft.Extensions.Options NuGet package. The problem is that package carries a hell of a lot of dependencies which seem rather excessive to add just for the sake of one interface.
So, the question ultimately is, "is there another approach I can take to configure a DI service located in .NET Framework class library which is not dependency heavy?
Check this article written by Filip Wojcieszyn.
https://www.strathweb.com/2016/09/strongly-typed-configuration-in-asp-net-core-without-ioptionst/
You add extension method:
public static class ServiceCollectionExtensions
{
public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new()
{
if (services == null) throw new ArgumentNullException(nameof(services));
if (configuration == null) throw new ArgumentNullException(nameof(configuration));
var config = new TConfig();
configuration.Bind(config);
services.AddSingleton(config);
return config;
}
}
Apply it in configuration:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.ConfigurePOCO<MySettings>(Configuration.GetSection("MySettings"));
}
And then use it:
public class DummyService
{
public DummyService(MySettings settings)
{
//do stuff
}
}
I bumped into this problem a little while ago, if you can even call it a problem really. I think we all tend to get a little shell-shocked when we see a dependency list like that. But as #Tseng mentioned, it's really not a big deal to include a bunch of extra tiny assemblies (they'll be included in the bin already anyways by virtue of a reference in another project). But I will admit it's annoying to have to include them just for the options interface.
How I solved it was by resolving the service dependency in startup.cs and adjust the service's constructor accordingly:
services.AddTransient<MyService>(Configuration.GetConfiguration("MyConfiguration"));
If you don't care about whatever IOptions provides you, why not just inject IConfiguration into your service?
public class MyService
{
private readonly IConfiguration _config;
public MyService(IConfiguration config)
{
_config = config;
}
public void DoSomething()
{
var value = _config["SomeKey"];
// doing something
}
}

Get HttpContext in AspNet Core 1.0.0 outside a Controller

I need to get the HttpContext in AspNet Core outside a controller. In the older AspNet 4 I could get it using HttpContext.Current, but it seems to be removed in the new AspNet. The only workaround I have found is resolving an IHttpContextAccessor by dependency injection and asking it the HttpContext, but to inject the IHttpContextAccessor I need to add IHttpContextAccessor as a singleton in the application Startup:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
I researched it and this is the only way I found. I google it and IHttpContextAccessor was removed as a default in the dependency resolver because it is very heavy dependency. Is there any other way to achieve this?
Edit:
I wonder if instead of adding it as a Singleton to the dependency resolver, I could get in that same place the instance of the HttpContextAccessor to save it in my own singleton class?
If you are porting a legacy application to ASP.Net Core that is reasonably complex, it would require totally reengineering to work properly with the .Net Core DI system. If you don't want to do this, you can 'cheat' by making this functionality global again in a Service Locator. To do this (which is not recommended if you can avoid it):
public class RequestContextManager
{
public static RequestContextManager Instance { get; set; }
static RequestContextManager()
{
Instance = new RequestContextManager(null);
}
private readonly IHttpContextAccessor contextAccessor;
public RequestContextManager(IHttpContextAccessor contextAccessor)
{
this.contextAccessor = contextAccessor;
}
public HttpContext CurrentContext
{
get
{
if (contextAccessor == null)
return null;
return contextAccessor.HttpContext;
}
}
}
// In Startup.cs
public void Configure(IApplicationBuilder app,...)
{
...
RequestContextManager.Instance = new RequestContextManager(app.ApplicationServices.GetService<IHttpContextAccessor>());
...
}
// In your code
var httpContext = RequestContextManager.Instance.CurrentContext;
For HttpContext to be valid, the program flow calling your class must originate in a controller or some middleware component. You could just pass a reference to HttpContext to your class.
To directly answer the question of why, this GitHub Announcement states that it's non-trivial to keep the HttpContext state tracked in IHttpContextAccessor. So it was moved to as-needed only. The HttpContext is still available in a Controller, however, without this being injected.
I don't believe you're pulling in a new dependency on the project level, just into classes via dependency injection, or grabbing it from IServiceProvider when you need it.

How to resolve EF7 current database context in ASP NET 5 out of the controller?

I want to get one context per request in ASP NET 5/EF 7 app for use it in some methods (not in controller).
Unfortunately I did not find the answer in the documentation
ASP.NET vNext template and examples aspnet/MusicStore
You may use some methods for achieving this purpose.
Using .AddDbContext<ApplicationDbContext>(); method for registering ApplicationDbContext in Dependency Injection system (in ConfigureServices() method), leads to the fact that it registered as Scoped dependence(or in another words "per request"). Thereby you only need get it from Dependency Injection system.
Add your dbContext as parameter of constructor method your class (in which you will use dbContext). Then you have to get this class using Dependency Injection system, e.g added it as parameter of controller's constructor.
public class HabitsController : Controller
{
public HabitsController(HabitService habitService)
{
}
}
public class HabitService
{
private GetHabitsContext _dbContext;
public HabitService(GetHabitsContext dbContext)
{
_dbContext = dbContext;
}
}
But if you don't want to use constructor injection for getting context, you can get necessary dependenses using GetService() method (but you need in ServiceProvider instance for that, in example below, i'am getting it through constructor injection too).
using Microsoft.Framework.DependencyInjection; // for beta 6 and below
using Microsoft.Extensions.DependencyInjection; // for beta 7 and above
public class HabitService
{
private IServiceProvider _serviceProvider;
public HabitService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public GetHabit()
{
var dbcontext = _serviceProvider.GetService<ApplicationDbContext>();
}
}
In first method, we can get HabitService through GetService() method too (not through the constructor injection).
using Microsoft.Framework.DependencyInjection; // for beta 6 and below
using Microsoft.Extensions.DependencyInjection; // for beta 7 and above
public class HabitsController : Controller
{
public HabitsController(IServiceProvider serviceProvider)
{
var habitService= serviceProvider.GetService<HabitService>();
}
}
public class HabitService
{
private GetHabitsContext _dbContext;
public HabitService(GetHabitsContext dbContext)
{
_dbContext = dbContext;
}
}
Thanks Tseng for remark:
I should be noted, that it's a pretty bad practice to inject the container into your objects. The container should only be referenced from the composition root and certain type of factories (which are implemented on application level, and not in the domain/business layer)
dbContext in HabitsController and _dbContext in HabitService are different contexts!
I checked, this is the same context.

Inject dependency in IStartupTask for bootstrapper

I am using Bootstrapper and Ninject to manage bootstrapping my application and dependency injection. This is an asp.net webapi application.
I have a simple implementation for IStartupTask like follows. The implementation of the ILog is been registered using Ninject. I want to know if there is a way to inject the ILog to the ContextBootstrap class?
public class ContextBootstrap : IStartupTask
{
public ILog Log { get; set; }
public ContextBootstrap(ILog log)
{
Log = log;
}
public void Run()
{
Log.Info("somehting");
}
public void Reset()
{
// do something here
}
}
I think IStartupTask internally uses the registered DI container to create instance of the concrete class, so the dependencies are injected via constructor.

Castle Windsor dependancy injection of nHibernate ISession into WebForms

I was wondering how to wire up Castle Windsor in WebForms.
I'm assuming that the second line wires up the controllers in MVC:
// Initialize Windsor
IWindsorContainer container = new WindsorContainer().Install(FromAssembly.This());
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container.Kernel));
How do I then wire up WebForms in ASP.NET?
I had a project which I have modified into an identical WebForms setup. Everything works up until the point where I want Castle Windsor to inject ISession into the ASPX page. It simply doesn't and I am under the assumption that the second line of code, above, is what does it for MVC controllers.
I have this in my nHibernate installer, in teh same place on both projects:
container.Register(Component.For<ISession>()
.LifeStyle.PerWebRequest
.UsingFactoryMethod(kernel => kernel.Resolve<ISessionFactory>().OpenSession()));
I had originally assumed this would do it but it is not the case.
I have been stuck on this for days and with very little official documentation on this I am close to ripping my hair out, what's left of it.
I do know the ASP.NET WebForms are not specifically designed to work with dependancy injection but Ninject have done it, albeit with a little hacking, if I can confirm that Castle Windsor is not compatible and/or will no longer support WebForms I will move to something else.
I managed to stuff Castle Windsor in to WebForms using the code here How to use Castle Windsor with ASP.Net web forms? It uses an an attribute to mark where a dependency should be injected in the a WebFrom.
I then used an MVP pattern. Each WebForm had a presenter
public partial class TestPage : UserControl, IShowTestPage
{
[Inject]
public TestPagePresenter Presenter { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack) return;
this.Presenter.OnViewInitialized();
}
public string TestMessage
{
get { return litTestMessage.Text; }
set { litTestMessage.Text = value; }
}
}
As the Presenter is resolved form the container, it is then back to normal for wiring up the dependencies
public interface IShowTestPage {
string TestMessage { get; set;}
}
public class TestPagePresenter {
private ISession session;
public TestPagePresenter(ISession session) {
this.session = session;
}
private IShowTestPage view;
public IShowTestPage { set { view = value; } }
public void OnViewInitialized {
TestMessage = session.Query("some database query");
}
}
My solution was based on a great article by Billy McCafferty