Unity - How to enable setter injection in configuration file? - asp.net-mvc

I've created a controller factory and registered my types in code. I can do the following:
public class HomeController : Controller
{
public MasterEntities DbContext { get { return Container.Resolve<MasterEntities>(); }
}
public ActionResult Index()
{
//DbContext can be used here properly...
}
}
However I would like to have the property injected in the setter instead of having to call Container.Resolve<TypeName>() explicitly. Preferrable without using attributes or some configuration in code...
public MasterEntities DbContext { get; set; }
How can this be configured in my .config file? Or does this require the use of attributes or configuration in code?

<register type="HomeController">
<property name="DbContext" />
</register>
should do the trick.

Related

Get Multiple Connection Strings in appsettings.json without EF

Just starting playing with the .Net Core RC2 by migrating a current MVC .Net app I developed. It looks like to me because of the way that configuration is handled with appsettings.json that if I have multiple connection strings I either have to use EF to retrieve a connectionstring or I have to create separate classes named for each connection string. All the examples I see either use EF (which doesn't make sense for me since I will be using Dapper) or the example builds a class named after the section in the config. Am I missing a better solution?
"Data": {
"Server1": {
"ConnectionString": "data source={server1};initial catalog=master;integrated security=True;"
},
"Server2": {
"ConnectionString": "data source={server2};initial catalog=master;integrated security=True;"
}
}
Why would I want to build two classes, one named "Server1" and another "Server2" if the only property each had was a connectionstring?
There are a couple of corrections that I made to Adem's response to work with RC2, so I figured I better post them.
I configured the appsettings.json and created a class like Adem's
{
"ConnectionStrings": {
"DefaultConnectionString": "Default",
"CustomConnectionString": "Custom"
}
}
and
public class ConnectionStrings
{
public string DefaultConnectionString { get; set; }
public string CustomConnectionString { get; set; }
}
most of Adem's code comes out of the box in VS for RC2, so I just added the line below to the ConfigureServices method
services.Configure<Models.ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));
The main missing point is that the connection string has to be passed to the controller (Once you’ve specified a strongly-typed configuration object and added it to the services collection, you can request it from any Controller or Action method by requesting an instance of IOptions, https://docs.asp.net/en/latest/mvc/controllers/dependency-injection.html)
So this goes to the controller,
private readonly ConnectionStrings _connectionStrings;
public HomeController(IOptions<ConnectionStrings> connectionStrings)
{
_connectionStrings = connectionStrings.Value;
}
and then when you instantiate the DAL you pass the appropriate connectionString
DAL.DataMethods dm = new DAL.DataMethods(_connectionStrings.CustomConnectionString);
All the examples show this, they just don't state it, why my attempts to pull directly from the DAL didn't work
I don't like the idea of instantiating the DAL. Rather, I'd do something like this
public class ConnectionStrings : Dictionary<string, string> { }
And something like this in the ctor of the DAL
public Dal(IOptionsMonitor<ConnectionStrings> optionsAccessor, ILogger<Dal> logger)
{
_connections = optionsAccessor.CurrentValue;
_logger = logger;
}
and you'll need to register with IoC
services.Configure<ConnectionStrings>(configuration.GetSection("ConnectionStrings")); /* services is the IServiceCollection */
Now you have all the connection strings in the DAL object. You can use them on each query or even select it by index on every call.
You can use Options to access in DAL layer. I will try to write simple example(RC1):
First you need to create appsettings.json file with below content:
{
"ConnectionStrings": {
"DefaultConnectionString": "Default",
"CustomConnectionString": "Custom"
}
}
Then create a class:
public class ConnectionStrings
{
public string DefaultConnectionString { get; set; }
public string CustomConnectionString { get; set; }
}
And in Startup.cs
private IConfiguration Configuration;
public Startup(IApplicationEnvironment app)
{
var builder = new ConfigurationBuilder()
.SetBasePath(app.ApplicationBasePath)
.AddJsonFile("appsettings.json");
Configuration = builder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
// ....
services.AddOptions();
services.Configure<ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));
}
Finally inject it in the DAL class:
private IOptions<ConnectionStrings> _connectionStrings;
public DalClass(IOptions<ConnectionStrings> connectionStrings)
{
_connectionStrings = connectionStrings;
}
//use it

ASP.NET 5 Dependency Injection - Where is the Activate Attribute?

ScottGu showed a feature in vNext to use the Activate Attribute like this:
public class HomeController : Controller
{
[Activate]
public TimeService TimeService { get; set; }
}
I'm on beta-8 and I can't seem to find this attribute, did it get removed?
In addition to using the renamed [FromServices] annotation on your properties, you can also utilize constructor injection:
public class HomeController : Controller
{
private TimeService _timeService;
public HomeController(TimeService timeService)
{
_timeService = timeService;
}
}
I prefer this approach since ASP.NET 5 will fail to construct HomeController if it cannot find TimeService, rather than failing later with timeService being null.
Found it...changed to [FromService]

Strongly typed AppSettings Configuration in ASP.NET 5

When using WebApi 2 my web.config was
<connectionStrings>
<add name="RavenHQ" connectionString="Url=http://localhost:8080;Database=ModelFarmDb" />
</connectionStrings>
For ASP.NET 5.0, I can't work out how to write the config.json file to do the same thing.
I've tried
{
"Data": {
"RavenHQ": {
ConnectionString: "Url=http://localhost:8080;Database=ModelFarmDb"
}
}
}
but it doesn't work. Any suggestions on how to directly map the web.config sections to config.json so as not to break other libraries that assume a web.config?
The app is running under IIS Express locally and is a web app on Azure.
Many thanks!
You accomplish this in asp.net 5.0 in a different way. I used json file for this example. If you need add xml file just use these package Microsoft.Framework.Configuration.Xml and use .AddXmlFile() method
This example uses beta 7
Create an AppSetting class
public class AppSetting
{
public string Setting1 { get; set; }
public string Setting2 { get; set; }
}
In your startup file add the json file with the configuration on this example is call config.json
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
var builder = new ConfigurationBuilder()
.SetBasePath(appEnv.ApplicationBasePath)
.AddJsonFile("config.json")
.AddXmlFile("thefilename")
.AddJsonFile($"config.{env.EnvironmentName}.json", optional: true);
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
Then you need to add the app service your AppSetting class so it can be injected
for later use
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
Then in your controller or where ever you need the configuraton inject the IOptions<AppSettings>
public class SampleController : Controller
{
private readonly AppSettings _appSettings;
public SampleController(IOptions<AppSettings> appSettings)
{
_appSettings = appSettings.Value;
}
}
and this is how the json looks like
{
"AppSetting": {
"Setting1": "Foo1",
"Setting1": "Foo1"
}
}
I took these peaces of code from live.asp.net in github

EF6 OnModelCreating() event doesnt

I am following along to this tutorial on EF6 and Codefirst. http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application
I started a solution and just added the Models, the contexts and the initializer
namespace TestContoso.DAL
{
public class SchoolContext : DbContext
{
public SchoolContext()
: base("Name=SchoolContextDB")
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Course> Courses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}
and created a dummy Home Controller and Index view.
namespace TestContoso.Controllers
{
public class HomeController : Controller
{
private SchoolContext db = new SchoolContext();
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
}
}
I have also set the Connection String and set the initializer in web.config
<entityFramework>
<contexts>
<context type="TestContoso.DAL.SchoolContext, TestContoso">
<databaseInitializer type="TestContoso.DAL.SchoolInit, TestContoso"/>
</context>
</contexts>
When I run the solution, my expectation is that the database would get created, however I notice that the OnModelCreating event never fires so the db is never created. Why isn't the db getting created? How would I cause the Code First migration to fire?
The article gives you an alternative. Try the alternative method of adding the initialization strategy via code to see if that works.
As an alternative to setting the initializer in the Web.config file is to do it in code by adding a Database.SetInitializer statement to the Application_Start method in in the Global.asax.cs file.
Database.SetInitializer(new CreateDatabaseIfNotExists<SchoolContext>());
And as specified in the comments. Run a query against the data or follow the section on 'Set up EF to initialize the database with test data' to automatically seed the database.
The OnModelCreating event only seemed to get fired when there was some query querying that model, to test that I just added a dummy query in the Index controller and it worked.
public class HomeController : Controller
{
private SchoolContext db = new SchoolContext();
//
// GET: /Home/
public ActionResult Index()
{
var students = from s in db.Students
select s;
return View();
}
}
}

Inheriting from controller, overriding save method with different type

I have a project that has a 'core' version, and a 'customised' version.
They are separate projects.
'customised' inherits functionality from 'core' and in some case overrides methods.
For example:
I have a user model that looks like this:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Then, in a separate assembly,
public class User : Core.User
{
public string CustomProperty { get; set; }
}
I then have a controller (in my 'core' assembly)
public class UserController : Controller
{
[HttpPost]
public ActionResult SaveUser(User user)
{
}
}
In my other project, I have a UserController that inherits from Core.UserController:
public class UserController : Core.UserController
{
[HttpPost]
public ActionResult SaveUser(Custom.User user)
{
}
}
Obviously, in my Global.asax I have the controller namespaces mapped
However, when I hit the SaveUser method, I get
The current request for action SaveUser on controller type
UserController is ambiguous between the following action methods
While I understand the problem, is there any way around this?
In a nutshell:
I want to use Core.UserController methods most of the time, but in this instance, I need to use my Custom.UserController SaveUser method (since it takes my Custom.User type)
Polymorphism?
public class UserController : Controller
{
[HttpPost]
public virtual ActionResult SaveUser(User user)
{
}
}
public class UserController : Core.UserController
{
[HttpPost]
public override ActionResult SaveUser(User user)
{
var customUser = user as Custom.User;
if(customUser != null)
{
//Your code here ...
}
}
}
Another possible workaround if the polymorphism solution doesn't work or isn't acceptable, would be to either rename your UserController or its action method to something slightly different:
public class CustomUserController : Core.UserController
{
[HttpPost]
public ActionResult SaveUser(Custom.User user)
{
}
}
public class UserController : Core.UserController
{
[HttpPost]
public ActionResult SaveCustomUser(Custom.User user)
{
}
}
If you wanted to keep the routes consistent with the other project, you would just have to create a custom route for this.
I encountered the same problem in my own project today and came across your post.
In my case, while I didn't want to alter the way the core controller's logic functioned, I was able to make changes to its code, and thus its modifier keywords. After adding virtual to the base controller's actions, and override to my derived controller's actions. The original controller's actions still function, my derived controller uses my customized actions, no more ambiguous errors.
I realize you may not be able to modify your Core controller, and if this is the case, then you need to differentiate your actions using some other means. Action name, parameters or some other solution such as a custom implementation of ActionMethodSelectorAttribute. That was my first attempt at this problem, but before I got too far down that path of how to implement it, I discovered the virtual/override solution. So I don't have code to share on that route unfortunately.

Resources