I am creating Asp.net core application and trying to connect to the database. I am getting an error at the following line of code in ConfigureServices method in the startup.cs file. The error that I am getting is the value cannot be null. It seems like it cant find the CustomerOrderEntities key in the web.config file. Not sure what the problem is
services.AddDbContext<CustomerOrderEntities>(options =>
options.UseSqlServer(Configuration.GetConnectionString("CustomerOrderEntities")));
Startup.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddDbContext<CustomerOrderEntities>(options =>
options.UseSqlServer(Configuration.GetConnectionString("CustomerOrderEntities")));
AutoMapperConfiguration.Configure();
// Create the container builder.
var builder = new ContainerBuilder();
// Register dependencies, populate the services from
// the collection, and build the container. If you want
// to dispose of the container at the end of the app,
// be sure to keep a reference to it as a property or field.
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>();
builder.RegisterType<DbFactory>().As<IDbFactory>();
builder.RegisterType<CustomerRepository>().As<ICustomerRepository>();
builder.RegisterType<ProductRepository>().As<IProductRepository>();
builder.RegisterType<OrderRepository>().As<IOrderRepository>();
builder.Populate(services);
this.ApplicationContainer = builder.Build();
// Create the IServiceProvider based on the container.
return new AutofacServiceProvider(this.ApplicationContainer);
}
Web.Config
<connectionStrings>
<add name="CustomerOrderEntities" connectionString="metadata=res://*/EF.CustomerOrderContext.csdl|res://*/EF.CustomerOrderContext.ssdl|res://*/EF.CustomerOrderContext.msl;provider=System.Data.SqlClient;provider connection string="data source=test-PC\MSSQLSERVER2014;initial catalog=CodeFirstTest;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
Connection string in ASP.NET Core is defined in appsettings.json, for example:
"ConnectionStrings": {
"CustomerOrderEntities": "Server=(localdb)\\mssqllocaldb;Database=aspnet-a3e892a5-6a9c-4090-bc79-fe8c79e1eb26;Trusted_Connection=True;MultipleActiveResultSets=true"
},
In your case name of connecting string is CustomerOrderEntities, you get null, probably it's not there, check you appsettings.json.
Your connectionstring in Appsettings.json is definitely missing. You cannot set connection string in web.config in Asp.net core whether you are targeting full .net framework or .net core. Alternative you type the connection string value in services.AddDbContext(options =>
options.UseSqlServer("Your Connectionstring"));
for more information check here;
https://learn.microsoft.com/en-us/ef/core/
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 installed the hangfire with Nuget.
PM> Install-Package Hangfire
Then updated the OWIN Startup class with the following lines:
public void Configuration(IAppBuilder app)
{
GlobalConfiguration.Configuration.UseSqlServerStorage("MySqlConnection");
app.UseHangfireDashboard();
app.UseHangfireServer();
}
I named the connection string name on the web.config as the name of the connectionString In UseSqlServerStorage.
web.config:
<connectionStrings>
<add name="MyEntities" connectionString="metadata=res://*/CRMModelContext.csdl|res://*/CRMModelContext.ssdl|res://*/CRMModelContext.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=xxx;persist security info=True;user id=sa;password=123;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
<add name="MySqlConnection" connectionString="User ID=sa;Initial Catalog=xxx;Password=123;Integrated Security=False;Data Source=." />
SQL Server 2008 R2 is installed on the system but The database for the hangfire is not in it.
Finally, when I run the program, the error below.
My Job:
BackgroundJob.Enqueue<Receiver>(x=>x.EmailReceiving());
RecurringJob.AddOrUpdate<Receiver>(x => x.EmailReceiving(), Cron.MinuteInterval(15));
error:
JobStorage.Current property value has not been initialized. You must set it before using Hangfire Client or Server API.
I had struggled to find the right solution online, then after asking around, I realized that I should create the datatable on the server by myself, then the tables will be created by hangfire after the application started.
Basically, there are 3 main lines of code that I put in my application to make the hangfire works:(.netcore web application) (in the startup.cs)
public void ConfigureServices(IServiceCollection services)
{
......
string connectionString = "getYourConnectionStringHere";
services.AddHangfire(x => x.UseSqlServerStorage(connectionString));
services.AddHangfireServer();
......
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
....
app.UseHangfireDashboard("/hangfire"); //this is to set the url for hangfire, e.g. localhost://xxxx/hangfire
...
}
GlobalConfiguration.Configuration.UseSqlServerStorage("MySqlConnection"); is using MySqlConnection as a connection string, not the value of MySqlConnection!
Are you using MsSql Server or MySql Server?
Try :
GlobalConfiguration.Configuration.UseSqlServerStorage(ConfigurationManager.ConnectionStrings["MySqlConnection"].ConnectionString);
I have a new application that I am building on ASP.NET Core with Entity Framework Core. The application has a UI, model, business, and data tier. In previous versions of ASP.NET, you could set the connection string in the web.config and it would be available in referenced tiers by default. This does not appear to be the same case in ASP.NET Core with appsettings.json (or other config options)? Any idea on how this is accomplished? I have the dbcontext configured in the data layer, but I am current hard-coding the connection string.
All examples I have see out there has the dbcontext configured in the UI layer in startup.cs. This is what I am trying to avoid.
The question Here got off topic.
You can easily add an extension method of IServiceCollection into your business/services layer and use it to register its own dependencies. Then in the startup you just call the method on the service layer without having any reference to EntityFramework in your web app.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace your.service.layer
{
public static class MyServiceCollectionExtensions
{
public static IServiceCollection AddMyServiceDependencies(this IServiceCollection services, string connectionString)
{
services.AddEntityFrameworkSqlServer()
.AddDbContext<YourDbContext>((serviceProvider, options) =>
options.UseSqlServer(connectionString)
.UseInternalServiceProvider(serviceProvider)
);
return services;
}
}
}
Startup:
using your.service.layer;
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("EntityFrameworkConnectionString");
services.AddMyServiceDependencies(connectionString);
}
Now your web app only needs a reference to your business/service layer and it is not directly dependent on EntityFramework.
I have a .NET Web solution with an Azure Cloud Service project and a single webrole. I deploy it to the East coast West coast data/compute centers for failover purposes and have been asked to automate the deployment using Powershell MSBuild and Jenkins.
The problem is i need to change the Sql Azure database connectionString in the Web.config prior to packaging and publishing to each deployment. Seems simple enough.
I understand that the webrole properties Settings tab allows you to add custom configuration properties to each deployment with a type of either "string" or "Connection String" but it looks like the "Connection String" option applies to only Blob, Table or Queue storage. If I use the "String" and give it an Sql Azure connection string type it writes it out as an key/value pair and Entity Framework and the Membership Provider do not find it.
Is there a way to add a per-deployment connection string setting that points to Sql Azure?
Thanks,
David
Erick's solution is completely valid and I found an additional way to solve the problem so I thought I'd come back and put it up here since I had such trouble finding an answer.
The trick is getting the Entity Framework and any providers like asp.net Membership/profile/session etc... to read the connection string directly from the Azure service configuration rather than the sites web.config file.
For the providers I was able to create classes that inherit the System.Web.Providers.DefaultMembershipProvider class and override the Initialize() method where I then used a helper class I wrote to retrieve the connection string using the RoleEnvironment.GetConfigurationSettingValue(settingName); call, which reads from the Azure service config.
I then tell the Membership provider to use my class rather than the DefaultMembershipProvider. Here is the code:
Web.config:
<membership defaultProvider="AzureMembershipProvider">
<providers>
<add name="AzureMembershipProvider" type="clientspace.ServiceConfig.AzureMembershipProvider" connectionStringName="ClientspaceDbContext" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
Note the custom provider "AzuremembershipProvider"
AzuremembershipProvider class:
public class AzureMembershipProvider : System.Web.Providers.DefaultMembershipProvider
{
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
string connectionStringName = config["connectionStringName"];
AzureProvidersHelper.UpdateConnectionString(connectionStringName, AzureProvidersHelper.GetRoleEnvironmentSetting(connectionStringName),
AzureProvidersHelper.GetRoleEnvironmentSetting(connectionStringName + "ProviderName"));
base.Initialize(name, config);
}
}
And here's the helper class AzureProvidersHelper.cs:
public static class AzureProvidersHelper
{
internal static string GetRoleEnvironmentSetting(string settingName)
{
try
{
return RoleEnvironment.GetConfigurationSettingValue(settingName);
}
catch
{
throw new ConfigurationErrorsException(String.Format("Unable to find setting in ServiceConfiguration.cscfg: {0}", settingName));
}
}
private static void SetConnectionStringsReadOnly(bool isReadOnly)
{
var fieldInfo = typeof (ConfigurationElementCollection).GetField("bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
if (
fieldInfo != null)
fieldInfo.SetValue(ConfigurationManager.ConnectionStrings, isReadOnly);
}
private static readonly object ConnectionStringLock = new object();
internal static void UpdateConnectionString(string name, string connectionString, string providerName)
{
SetConnectionStringsReadOnly(false);
lock (ConnectionStringLock)
{
ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings["name"];
if (connectionStringSettings != null)
{
connectionStringSettings.ConnectionString = connectionString;
connectionStringSettings.ProviderName = providerName;
}
else
{
ConfigurationManager.ConnectionStrings.Add(new ConnectionStringSettings(name, connectionString, providerName));
}
}
SetConnectionStringsReadOnly(true);
}
}
The key here is that the RoleEnvironment.GetConfigurationSettingValue reads from the Azure service configuration and not the web.config.
For the Entity Framework that does not specify a provider I had to add this call to the Global.asax once again using the GetRoleEnvironmentSetting() method from the helper class:
var connString = AzureProvidersHelper.GetRoleEnvironmentSetting("ClientspaceDbContext");
Database.DefaultConnectionFactory = new SqlConnectionFactory(connString);
The nice thing about this solution is that you do not end up having to deal with the Azure role onstart event.
Enjoy
dnash
David,
A good option is to use the Azure configurations. If you right click on the Azure project, you can add an additional configuration. Put your connection string(s) in the correct configuration (e.g., ServiceConfiguration.WestCoast.cscfg, ServiceConfiguration.EastCoast.cscfg, etc).
In your build script, pass the TargetProfile property to MSBuild with the name of the configuration, and those settings will be built into the final cscfg.
Let me know if you run into any problems. I did the approach, and it took a few tries to get it working right. Some details that might help.
Erick
I am having an ASP.NET MVC 3 application that collaborates with a WCF service, which is hosted using Autofac host factory. Here are some code samples:
.svc file:
<%# ServiceHost
Language="C#"
Debug="true"
Service="MyNamespace.IMyContract, MyAssembly"
Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>
Global.asax of the WCF service project:
protected void Application_Start(object sender, EventArgs e)
{
ContainerBuilder builder = new ContainerBuilder();
//Here I perform all registrations, including implementation of IMyContract
AutofacServiceHostFactory.Container = builder.Build();
}
Client proxy class constructor (MVC side):
ContainerBuilder builder = new ContainerBuilder();
builder.Register(c => new ChannelFactory<IMyContract>(
new BasicHttpBinding(),
new EndpointAddress(Settings.Default.Url_MyService)))
.SingleInstance();
builder.Register(c => c.Resolve<ChannelFactory<IMyContract>>().CreateChannel())
.UseWcfSafeRelease();
_container = builder.Build();
This works fine until I want WCF service to allow or require sessions ([ServiceContract(SessionMode = SessionMode.Allowed)], or [ServiceContract(SessionMode = SessionMode.Required)]) and to share one session with the MVC side. I changed the binding to WSHttpBinding on the MVC side, but I am having different exceptions depending on how I tune it.
I also tried changing AutofacServiceHostFactory to AutofacWebServiceHostFactory, with no result.
I am not using config file as I am mainly experimenting, not developing real-life application, but I need to study the case. But if you think I can achieve what I need only with config files, then OK, I'll use them.
I will provide exception details for each combination of settings if required, I'm omitting them not to make the post too large. Any ideas on what I can do?