ASP.NET Core UI App with separate data .dll - c#

I'm in the process of moving the UI side of an application to the new ASP.NET Core MVC structure. Unfortunately, I still need to reference a data layer which is built in the prior-generation ASP.NET framework. This data .dll has the appropriate connection strings to various databases all being managed by ConfigurationManager.ConnectionStrings["ConnectionStringName"].ConnectionString which required me to mimic in the UI layer in order to actually get at the data.
Now, with ASP.NET Core MVC, the web.config for configuration has been replaced with the appsettings.json file.
That paradigm shift breaks all my access to data since I can no longer replicate the connection string in the UI application.
Is there an appropriate solution that can make this data layer .dll more self-contained and rely on its own, internally defined connection string(s), while still exposing the Methods to the "containing" application - in this case, the UI layer?

Actually you do have reference to your connection string from the new .json file. You will do something like:
var builder = new ConfigurationBuilder();
builder.AddInMemoryCollection();
var config = builder.Build();
config["somekey"] = "somevalue";
// do some other work
var setting = config["somekey"]; // also returns "somevalue"
here is a link: docs.asp.net

I have resolved my issue with a work-around, and it will do for now. Ultimately, I'd like to find a better option, but I'm moving forward which makes my boss happy.
I ended up changing my method signatures to accept a string value representing the connection string that's no longer in the calling project because of the conversion to Core MVC.
In the called .dll, the code now looks to see if there is a value to the passed parameter, and, if so, uses the passed value to initialize the SqlConnection. If no parameter is provided, it will look to the config section in web.config using the ConfigurationManager capabilities.
This will allow the existing project to use the code, as well as the new Core MVC project. It's a bit kludgy, but functional.

Related

How to access environment variable at data access layer in .NET Core

My project is based on .NET Core WEB API and it has 3 layers within it i.e. The controllers, Business layer & Data layer.
I have introduced paging in WEB API so that data can be retrieved in batches. The page size is the one I'm looking forward to keep it configurable in one of configuration file.
I'm carrying my paging operation at data access layer and want to read that environment variable.
Is it good practice to do so and in what way I can achieve it ?
Any help or pointers are welcomed.
The preferred way to do this is via the .NET Core configuration. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0
You can have the default values set in your configuration file but they can also be overridden by environment variables.
You can also bind the configuration sections to a POCO as described here. https://medium.com/#dozieogbo/a-better-way-to-inject-appsettings-in-asp-net-core-96be36ffa22b
This will give you a strongly typed configuration object which is easier to work with.

How to using Asp.net Identity when using Business And DataModel Layer

I'm creating application with layered architecture. I have separate
+ 'DataModel' project with only model classes
+ 'BusinessLogic' project that containing my business
+ 'Core' project for run Business from ui
+ 'ViewModel' project
+ 'Web' project with asp.net core application.
My goal was to separate these projects so that Web project knows nothing about DataModel so the Web project should just reference Core and ViewModel. Everything was great until I configured Asp.Net Identity - in order to configure authorization I had to reference DataModel project which I had wanted to avoid. Is it possible to achieve my goal, and (if so) how to do it.
Note:
I'm using this how to separate model library when using asp.net identity for writing my question and i don't find accepted answer as my answer!
When you create a website that uses Identity directly, you must provide it with various Identity "stores": UserStore<TUser>, RoleStore<TRole>, etc. The default and easiest approach is to use Entity Framework Core as the backing for the store(s), and Identity comes with built-in stores to work with EF Core. However, using that requires access to the context, which means you then will need a dependency on your data layer. There is no way around that when using AddEntityFrameworkStores<TContext>.
If you want to keep your data layer abstracted, then you will need to either 1) use a centralized identity provider, such as IdentityServer or 2) create custom stores.
IdentityServer, for example, supports using both EF and Identity as a backing. That does mean it will need a dependency on your data layer, but IdentityServer would be exist in a separate project. Your actual website would handle auth via IdentityServer endpoints, and therefore would have no dependency on your data layer. In fact, it doesn't even know or care that you're using Identity at all at that point.
Creating custom stores will be a bit more difficult, obviously, and unless you provide an true abstraction layer, you'll still ultimately end up with a dependency on your data layer. That might be something like a microservice(s), where the store will actually make HTTP requests to the service to get the objects it needs, instead of making database queries directly. The microservices, then, will hold the data dependency.
One thing you might not be considering in this is that the dependency is there even without a direct reference. For example, if your Core project uses stuff from your DataModel project, and then your Web project uses stuff from your Core project, your web project has an implicit dependency on your DataModel project. If you look at the bin folder after building, for example, you're see a DLL for your DataModel project and even one for EF Core there, despite not explictly using either one in your Web project. In this case, using separate projects helps only to division the logic in perhaps a more succinct and understandable way, but it does not serve to actually abstract any dependencies.

How exactly does Microsoft.Extensions.Configuration dependent on ASP.NET Core?

Does ASP.NET Core implement IConfiguration access to config values?
Most likely my question arose because I don't understand what exactly ASP.NET Core is. Well, I know it's a web framework, Not sure, but looks like it is a namespace in .NET, or a package... I know in php, a framework could be a set of classes (a namespace) or compiled library which is provided as an extension so I presume a similar approach in .NET.
Initially, I didn't intend to wrap my head around ASP.NET Core yet. I needed to store some config for my simple console C# application (VS Code and .NET Core). I've found a lot of topics (for example here: How to read values from config.json in Console Application) that to read JSON (recommended) config. Given that, I added three necessary nugget packages:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.FileExtensions;
using Microsoft.Extensions.Configuration.Json;
I need to use:
new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json").Build();
This returns an object that implements the IConfigurationRoot/IConfiguration interface. But all the examples are given in an ASP.NET Core context. I have a really simple app and I don't need any of ASP.NET functionality yet.
So I've tried to access IConfigurationRoot without ASP.NET. The resulting object stores values from config file, but does not have all methods of its interface to access them.
How to explain this in context of .NET namespaces? Does ASP.NET Core implement methods to access values from IConfiguration like Get<T>()?
If Microsoft.Extensions.Configuration is part of or heavily dependent on Microsoft.AspNetCore.App, why is it in different namespace?
If I add ASP.NET Core (NuGet package and namespaces), will it be an overkill?
Maybe I should use soemthing other than ConfigurationBuilder to read JSON?
Microsoft.Extensions.Configuration, like other packages in the Microsoft.Extensions namespace (e.g. Options, or DependencyInjection), are packages that were created as part of the ASP.NET Core framework. The way ASP.NET Core and all its related packages were built however is in a very modular way, so all the libraries can be used within the ASP.NET Core context, or without.
You have to understand those packages just as libraries. They are included in ASP.NET Core since the framework builds on top of them, but if you do not need the ASP.NET Core web framework, you can still use those libraries separately without any mention of ASP.NET Core. That’s actually why they live inside the Microsoft.Extensions namespace instead of Microsoft.AspNetCore: They are completely separate projects. Of course, development of those packages is done by the ASP.NET Core team and the design decisions of ASP.NET Core do affect how those extension packages evolve; but the team is very careful with these packages so that the general use is not affected.
So that all being said, how do you use these packages? Just like any other library, you just add a NuGet reference to it. Since Microsoft.Extensions.Configuration is the base library which does not come with any facility to load files, you also need Microsoft.Extensions.Configuration.Json if you want to load JSON files.
But then it’s really straight forward:
var configuration = new ConfigurationBuilder()
.AddJsonFile("config.json")
.Build();
// retrieve configuration values
Console.WriteLine(configuration["foo"]); // bar
Console.WriteLine(configuration["baz:bar"]); // qux
For this example, the config.json looked like this:
{
"foo": "bar",
"baz": {
"bar": "qux"
}
}
So you can just load the configuration like this. Be sure to still check the documentation though. It may be about the configuration used inside of ASP.NET Core but the underlying concepts still apply (e.g. how configuration paths look like, or how binding works).
Finally, note that this is really just meant for configuration. Loading data from JSON is just one of many configuration sources you can with Microsoft.Extensions.Configuration. But regardless of what provider you will use, you will end up with the same configuration format that has the concepts of sections and key paths.
If you came to the package while looking how to parse JSON, then it’s likely that you are looking at the wrong tool. If you want to parse JSON to retrieve a proper data structure, like you would use when using JSON as a way to serialize data, then you should look at something different. The most common solution for parsing JSON (serializing too) is using Json.NET which is a very powerful and flexible tool to deal with any kind of JSON data.

where to write the connection string ? in app.config or in web.config?

I am developing MVC application.
I have two projects in my application.
one is MVC application contains, Controller and Views and the second one is DataLayer project.
I am confused about the where to write the connection string, because while publishing the application it takes the web.config file and I get the data from DataLayer project so should I add connection string in the app.config/Web.config of Data layer project ?
Also, would like to know what is the purpose and difference between app.config and web.config ?
Every project comes with a configuration file when it's created. A general class library has a generic one called app.config. A web project is more specific, so its file is called web.config and comes with web-specific parameters. They both serve the same purpose.
The problem you are facing is that only the executable project's config file (web.config) is deployed by default. You have a few options:
Add your connection string to web.config and pass it to your data layer. This is simple (an most common), but separates the config info from your data layer project.
Have your data layer read web.config using System.Configuration.ConfigurationManager. This alleviates you from passing the data to your data layer, but creates a strong dependency (your data layer will not work without a properly formatted web.config file).
Deploy app.config as XML content and write custom code so that your data layer can read it. This is more work, but it gets your data config out of the web config.
A slight change to #2, you can create a custom config section called "dataLayer" in web.config. This can be read via System.Configuration.ConfigurationManager. I prefer this approach, as it seems like a good balance. You have a custom strongly-typed config section in the "default" config file.
This related question has some good info too.
The connection string goes in the Web.config. By default it's going to look in the config of the executing assembly and ignore the config files of the referenced assemblies.
The config file for the referenced assembly may be used at design time. For example if you are using Entity Framework in your data layer assembly, it will store the connection information that is used to build the model from the database in the app.config.
I generally just copy that connection information over to the web.config when I get to the point that the web project is going to run and access the data through the data layer.
Web.Config is used for asp.net web projects / web services.
App.Config is used for Windows Forms, Windows Services, Console
Apps and WPF applications.
Add your connection string in Web.config of Data layer project
I'll answer your question first, and then move on to what is, IMO a more important consideration. For this particular use case, I prefer a DI pattern, in which the consumer tells the provider what the connection string is. This makes your data layer agnostic of the database, and allows it to talk to any data store that satisfies it's contracts. In short, since your MVC project is the consumer of the data layer, the connection string is stored in the web.config. BUT IT IS STORED ENCRYPTED!!!
Now then, there is actually a deeper issue here than where you physically write the connection string, and that is building an abstraction between your consuming code and the configuration store. If you do this, where you store your configuration values becomes essentially irrelevant.
I always create a Configuration class within each layer (project) that provides the configuration values consumed within that layer. This provides several benefits:
It allows for strongly-typed values when consuming them. If your configuration value is an int, you get an int, and you don't need to convert it when you consume it.
It allows for defaulting values that may have been inadvertently left out of the config file. This makes your code more robust.
It allows for flexibility in where you store the values. You could put some values in a config file, others in a database, and still more could be fetched from a remote web service. If you decide to change a store, you only have to edit the code in one place -- not every place the value is consumed.
As your solution grows and projects are added, the pattern scales well and keeps configurations segregated.
It removes magic strings from your code.
Instead of the following, which has a nasty magic string:
return System.Configuration.ConfigurationManager.AppSettings["DefaultUserName"];
you would write
MyApp.Configuration.DefaultUserName
Here is an example of a very basic implementation which returns a strong type (in this case, a DayOfWeek). It has a helper method to help you abstract the act of pulling from the store. If you needed to include multiple stores, this method would take a generic of type T where T is the type of store. In the below, simplified example, it just pulls from the config file:
public class Configuration
{
private const DayOfWeek FailsafeDefaultDayOfWeek = DayOfWeek.Saturday;
/// <summary>
/// A default for the day of week
/// </summary>
public static DayOfWeek DefaultDayOfWeek
{
get
{
string dayOfWeekString = GetSettingValue("DefaultDayOfWeek");
try
{
return (DayOfWeek)Enum.Parse(typeof(DayOfWeek), dayOfWeekString);
}
catch (Exception)
{
// If someone screws up and forgets to include a value, or the value cannot be cast:
return FailsafeDefaultDayOfWeek;
}
}
}
/// <summary>
/// Helper method to easily pull a value from a configuration store.
/// </summary>
/// <param name="settingName"></param>
/// <returns></returns>
private static string GetSettingValue(string settingName)
{
try
{
return System.Configuration.ConfigurationManager.AppSettings[settingName];
}
catch (Exception)
{
throw new MissingConfigurationValueException(settingName);
}
}
}

Override default connection string

In an MVC web application I want to override connection strings based on the development machine I'm using. I can use Web.config transformations, but I also need to override connection strings in various non-web config files. I can use the SlowCheetah extension, but then I will end up creating the same transformation for every project that accesses the database. This is a hassle to maintain when the project becomes bigger and has more developers.
What I would like to do is modify the way Entity Framework or ASP.NET look for connection strings, adding a class of my own that looks for connection strings, and only implement the transformation logic once. I would hopefully use Ninject to inject it only when relevant.
Is there such an "IConnectionStringProvider" interface I can implement and register, and automagically have ASP.NET and EF use it?
EDIT. I have found this, but it seems real nasty. If there's no cleaner way, I'll just use multiple identical configuration translations, and maybe let the source control system duplicate them properly.
You can tell Entity Framework to use a different connection string - it doesn't have to use the default one in web.config.
Here is an example: http://www.codeproject.com/Tips/234677/Set-the-connection-string-for-Entity-Framework-at
Here is another: http://msdn.microsoft.com/en-us/library/bb738533.aspx
It's up to you how you architect the rest of it.
Personally I use an app setting in web.config to tell my code which connection string to use for a particular part of the system, e.g.
var connectionStringNameForMyFeature = ConfigurationManager.AppSettings["connectionStringNameForMyFeature"];
myFeature.ConnectionString = ConfigurationManager.ConnectionStrings[connectionStringName];

Categories