.NET Core configuration differs greatly from the standard .NET projects. We don’t have anymore a web.config file but instead, we use a built-in Configuration framework that comes with the .NET Core.
Therefore having a good understanding of how to configure your project and how to configure the services, which you will use until the end of the development process, is a must.
In this post, we are going to explain how to use the configuration methods in the Startup class. Also, we are going to learn how to register different services and to use extension methods to help us in a process.
If you want to see all the basic instructions and complete navigation for this series, please click on the following link:Â Introduction page for this tutorial.
For the previous part click on this link:Â MySQL, creating database data
This post is divided into several parts:
- Creating a New Project and Modifying LaunchSettings.json File
- Program.cs and Startup.cs Explanations
- Extension Methods and CORS Configuration
- IIS Configuration
- Conclusion
Creating a New Project and Modifying LaunchSettings.json File
After we have finished creating and populating the database, in the previous post, we are going to create a Visual Studio project for our server part of the application. Open Visual Studio 2019 and create a new ASP.NET Core Web Application with the name AccountOwnerServer
:
In the next window, we are going to choose Web API and from the left drop-down list .NET Core. Also, from the right drop-down, we are going to choose ASP.NET Core 3.1. Finally, let’s click the Create button and the project will load:
After the project has been created, we are going to modify the launchSettings.json file which is quite an important file for the .NET Core configuration. Let’s change the applicationUrl
property and the launchBrowser
property to false, to prevent web browser to start when the project starts.
In the Solution Explorer expand the Properties and double click on the launchSettings.json
file. Let’s modify that file:
{ "$schema": "http://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:5000", "sslPort": 0 } }, "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": false, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "AccountOwnerServer": { "commandName": "Project", "launchBrowser": false, "applicationUrl": "http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } }
Program.cs and Startup.cs Explanations
In the Program.
cs we can find this piece of code:
public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
This code looks very similar to the version from ASP.NET Core 2.2 at first glance, but actually, many things changed. In version 3.0 ASP.NET Core has been rebuilt to use a Generic Host, instead of using a separate Web Host.
So basically, the CreateHostBuilder method has been broken into two logical parts:
- CreateDefaultBuilder(args) – ASP.NET Core uses this to configure the app configuration, logging, and dependency injection container
- ConfigureWebHostDefaults – This adds everything else required by a typical ASP.NET Core application (kestrel configuration, and using the Startup class, middleware pipeline…)
We can also notice this part of the code: UseStartup<Startup>()
. The Startup class is mandatory for the .NET Core, in which we configure embedded or custom services that our application needs. When we open the Startup
class, we can see the constructor and the two methods, which content we are going to change during the application development. In the method ConfigureServices
, we will do exactly that, configure our services. Furthermore, in the Configure method, we are going to add different middleware components to the application’s request pipeline.
All of our configuration code could be written inside the ConfigureServices
method, but large applications could potentially contain many services. As a result, it could make this method unreadable and hard to maintain. Therefore we will create extension methods for each configuration and place the configuration code inside those methods.
Extension Methods and CORS Configuration
An extension method is inherently the static method. They play a great role in .NET Core configuration because they increase the readability of our code for sure. What makes it different from the other static methods is that it accepts “this” as the first parameter, and “this” represents the data type of the object which uses that extension method. An extension method must be inside a static class. This kind of method extends the behavior of the types in .NET.
So, let’s start writing some code.
Let’s create a new folder Extensions
in the main project and a new class inside with the name ServiceExtensions
. We are going to make that class static and it will consist of our service extension methods:
namespace AccountOwnerServer.Extensions { public static class ServiceExtensions { } }
First, we need to configure CORS in our application. CORS (Cross-Origin Resource Sharing) is a mechanism that gives rights to the user to access resources from the server on a different domain. Because we will use Angular as a client-side on a different domain than the server’s domain, configuring CORS is mandatory. So, let’s add this code to the ServiceExtensions
class:
public static void ConfigureCors(this IServiceCollection services) { services.AddCors(options => { options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader()); }); }
We are using the basic settings for adding CORS policy because for this project allowing any origin, method, and header is quite enough. But we can be more restrictive with those settings if we want. Instead of the AllowAnyOrigin()
 method which allows requests from any source, we could use the WithOrigins("http://www.something.com")
 which will allow requests just from the specified source. Also, instead of AllowAnyMethod()
 that allows all HTTP methods, we can use WithMethods("POST", "GET")
 that will allow only specified HTTP methods. Furthermore, we can make the same changes for the AllowAnyHeader()
 method by using, for example, the WithHeaders("accept", "content-type")
 method to allow only specified headers.
IIS Configuration as Part of .NET Core Configuration
Additionally, we need to configure an IIS integration which will help us with the IIS deployment. Add the following code to the ServiceExtensions
class:
public static void ConfigureIISIntegration(this IServiceCollection services) { services.Configure<IISOptions>(options => { }); }
We do not initialize any of the properties inside the options because we are just fine with the default values. For more pieces of information about those properties, look at the explanation:
In the Startup class we are going to change the ConfigureServices
and Configure
methods:
public void ConfigureServices(IServiceCollection services) { services.ConfigureCors(); services.ConfigureIISIntegration(); services.AddControllers(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseCors("CorsPolicy"); app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.All }); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
In the ConfigureServices
method, CORS, and IIS configuration have been added. Furthermore, the CORS configuration has been added to the application’s pipeline inside the Configuration
method. But as you may notice, there is a little more code. Therefore, we are going to explain it now.
app.UseForwardedHeaders
will forward proxy headers to the current request. This will help us during the Linux deployment.app.UseStaticFiles()
enables using static files for the request. If we don’t set a path to the static files, it will use awwwroot
folder in our solution explorer by default.
Conclusion
Concerning the .NET Core configuration, we could say that this is quite enough. Now you know how to modify the launchSetting.json file, the purpose of the Program and the Startup classes, how to configure services, and finally how to create and use extension methods.
Thank you for reading and check out the next part in which we will create our first service, logger service, and use it for logging our messages.
Hello, I got error when add services.ConfigureCors(); to startup.cs
“Error CS7036 There is no argument given that corresponds to the required formal parameter”
Thanks
/Danny
Hello Danny, thank you a lot for reading this post. About your error, please check your extension method ConfigureCors for the missing “this” keyword in front of your “IServiceCollection services” parameter.
I think that you wrote your method like this “public static void ConfigureCors(IServiceCollection services)”
but it needs to be like this “public static void ConfigureCors(this IServiceCollection services)”
When I remove “this” keyword I get the same error as you are. So just check ConfigureCors method.
Thanks Marinko! Yes It’s working now
You are welcome Danny. It’s my pleasure to help.
Hi Marinko, this was greate article that help me to learn .NET Core from beginning.
But i still get same error. Could you please help me?what i’ve missed?
Hello Peter. If you have the same error as Danny did “Error CS7036” with the extension method, then you are missing “this” keyword in your extension method. If not, then please give me more information about your error because I can’t help you otherwise.
Hi Marinko, now it works. Thanks. 🙂
Hi Marinko
I’m working with part 2 of your series of tutorials. I’m getting the error “The name does not exist in the current context” for the ForwardHeaders.all and Path variables in the startup.cs page. Please advise what I’m missing.
Thanks for your excellent tutorial.
Matty
Hi Matty.
I would really want to help you, but it would be much easier if you could send me your solution. Or you could download my solution (provided in the post) and compare for differences. Again, I want to help but right now (based on your error message) I can’t figure it out. Upload the solution and post a link here, then I am going to check it out and for sure find what is missing.
One more time, thank you very much for reading the posts.
Hi Marinko
Thanks for that speedy response.
I think I managed to sort the problem out. Two missing references at the top of the page, one to system.io and one to microsoft.aspnetcore.httpoverrides. Hope that’s all it is.
Regards
Matt
Excellent Matty, I am glad you could sort it out by yourself. I thought that could be the problem but wasn’t that much sure. About a quick response, well it was 7 hours late, so not that quick, but in my deffence I was sleeping and just woke up an hour ago 😀
All the best,
Marinko.
looks like there isn’t part 2 available anymore on the provided github repo link
If you using this tutorial with VS2017 than the latest .NET SDK you can go with is v.2.2.107. It can be downloaded from here: https://dotnet.microsoft.com/download/dotnet-core/2.2#sdk-2.2.107
Where do you set that you’re using the MySQL driver and not the MSSQL driver?
Hello Eran. In this article nowhere. But in the Repository article I have stated that we need to instal a third party library Pomelo.EntityFrameworkCore.MySql to enable communication between .net core and mysql. And then in Startup class I have added:
var connectionString = config["mysqlconnection:connectionString"];(o => o.UseMySql(connectionString));
services.AddDbContext
As you can see, I am using o.UseMySql method here.
Isn’t the MySQL library enough?
You can use either MySQL Connector or Pomelo. I have used Pomelo because I worked with it before and it has a great support for .net core.
Ok. Right now, I’m getting “MySql.Data.MySqlClient.MySqlException (0x80004005): Unable to connect to any of the specified MySQL hosts.”
I just tried to mess up my MySQL connection string, and I get the same error when executing any query. So it might be related to your connection string or for any reason your MySQL server refuses connection, I can’t be sure. Check your server name or username and password and check wether you have spaces between parameters…
I checked again and removed the port specification from the connection string. That worked.
I am glad I could help, if I helped at all. Nice to hear you solved the problem.
Perfect !
When I move my server off my development machine, when I need to access it via an ip address, does it still need to listen on localhost?
Please have look at our articles about iis or linux deployment. You will find them in this series as well. You will find there how to configure deployment environment.
I tried looking over it but couldn’t find anything that helps.
I’m not using IIS. I’m running ASP.NET as a local application. It’s not meant to be a website but a web-based interface.
When I try to access the IP address of the computer, it says it can’t be reached. Is there any configuration I need to set?
Figured it out by adding “.UseUrls(“http://localhost:5000”, “http://ipaddress:5000″)” to the kestrel.
Why are you using MVC? I thought this was an API for an angular front end?
Hello Alexander. No we are not using MVC this is the Web API project. As you said it is an API for an angular front end. I believe you saw the AddMVC and UseMVC methods and thus your question. But in .NET Core 2.2 this is the way to configure your project. In ASP.NET Core 3.0 you don’t have that. Instead we have AddControllers() and UseEndpoints. Of course, you could use AddMvc and UseMvc but for the API project, it is not recommended.
The application that I’m writing has stopped working correctly and I can’t put a finger on what went wrong.
Previously, it would load the configuration, show it was listening to the ips and ports and block the command prompt as it was running.
Now, it’s only showing:
Config file is: *
Connection String: server=localhost; database=…; userid=…; password=…
Then it exits code 0
Can you point me in a direction to see how to fix this?
Noticing the differences between .NET Core 2 and 3. I do like the idea of service extension approach. But I did do a double take when
we were able to reference ‘AccountOwnerServer.Extensions’ and it’s seamless in Startup.cs ConfigureServices using one IServiceCollection object. Not complaining about relearning so long as its a smarter design.
Hello Brian. Well, I am a little bit struggling to undarstend why is this a problem for you. ASP.NET Core provides us with a single IServiceCollection object to use it for the service registration. All we do here is placing that logic in a separate class with extension methods to clear the ConfigureServices method. It has proven as a great solution in larg projects we have been working on. Especially, when you have to configure Swagger with authentication, Identity with so many rules, etc… As long as I am concerned, this would be my prefered way for service registration.
Hi Marinko, yes, this works for .NET Core 3.1 – now I’m trying with .NET 5.0. I’m using an Angular project to hit one end point in the API which, like I said, works with the .NET Core 3.1 project. I created a new .NET 5.0 project with your example and try to connect to an endpoint from the same Angular project and get a CORS error:
Access to XMLHttpRequest at ‘https://localhost:44342/register’ from origin ‘http://localhost:4200’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
Any ideas what I can try? I spent a few hours on this and I can’t get it. Any help is much appreciated!
Hello Kevin. I must say this is really strange. Right after I red your comment, I took our .NET Core project and updated it to the version 5. Then started the Angular project and hit the action without a problem. Of course, I had to update the Pomelo version to preview 5.0 (it is in prerelease version) and had to change the UseMySql method a bit, because they changed the implementation a bit. But other than that, everything works as it was before the update. Your error states the CORS problem, but I am not really sure why is that. If you can’t work it out, you can send your server project to me (link it on GitHub) and once I find some time, I will look at it.
Hi Marinko, OK, I have it working – I guess I was mixing examples. I started a new 5.0 project and exactly followed your article above and it works, pretty much as you say in your comment. I do apologize for not starting a new project and closely following the article before messaging you.
What I was trying to get working yesterday is the Identity example from your series, “Introducing Identity to the ASP.NET Core Project”. (Is that working for you in 5.0?) That will be my next attempt – start a new 5.0 project and get the Identity example working with registration and login working from Angular. The database creating part (including the User object) was working perfectly. I was encountering the CORS problem when trying to hit the registration end point. Like I said, I’ll start over and see if I can get it to work.
Hi Kevin. I’m glad you have it solved. Regarding your question, yes it works with .Net 5. Pretty much everything from 3.1 works in .Net 5, there were no big code changes in version 5. Every project I updated from 3.1 to 5 was working without a single problem or with pretty small modifications. Just pay attention that article you mentioned is for MVC project. We also have Angular with ASP.NET Core Identity series, so this one is better for you to follow if you are working with Angular and Web API. You can find the series in the Guides/Security menu.