Having a good understanding of how to configure your project and how to configure the services, that you will use until the end of the development process, is a must.
In this article, we will explain how to use the configuration methods in the Startup class. Also, we will learn how to register different services and use extension methods to help us in the process.
If you want to see all the basic instructions and complete navigation for this series, please check the Introduction page for this tutorial.
Let’s start.
Creating a New Project and Modifying the 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. Let’s open Visual Studio and create a new ASP.NET Core Web API project and in the next window name it AccountOwnerServer
.
Then in the next window, we have to provide a couple of information:
- Framework – for this series, we are going to choose .NET 6.0, but you can choose .NET 5 as well if you want to (the code is pretty much the same)
- Authentication type – we’ll leave it at None
- Configure for HTTPS – we will leave it checked
- We are not going to enable Docker
- Use controllers – we want to check this since we will use controllers in our API
- Enable OpenAPI support – we are going to uncheck this since we don’t want Swagger implementation now
After the project creation, we are going to modify the launchSettings.json
file which is quite an important file for the .NET configuration. Let’s change the applicationUrl
property to a new value and the launchBrowser
property to false
, to prevent a web browser from starting when the project starts.
In the Solution Explorer, let’s expand the Properties and double-click on the launchSettings.json
file:
{ "$schema": "https://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:40700", "sslPort": 44360 } }, "profiles": { "AccountOwnerServer": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, "launchUrl": "weatherforecast", "applicationUrl": "http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "IIS Express": { "commandName": "IISExpress", "launchBrowser": false, "launchUrl": "weatherforecast", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } }
For the sake of simplicity, we are using just http://localhost:5000
without the HTTPS URI. Feel free to leave the HTTPS address as well on 5001.
Program.cs Class Explanation
Let’s inspect the Program.
cs class, to see the code it contains:
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); var app = builder.Build(); // Configure the HTTP request pipeline. app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
When we compare this class to the same one from the .NET 5 version:
public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
We can see three main changes:
- Top-level statements
- Implicit using directives
- And there is no usage of the Startup class
“Top-level statements” means the compiler generates the namespace, class, and method elements for the main program in our application. You can read more about this in our Top Level Statements article.
“Implicit using directives” means the compiler automatically adds a different set of using directives based on a project type, so we don’t have to do that manually. We can find those using directives stored inside the obj/Debug/net6.0
folder with the ...GlobalUsings.g.cs
name part.
Finally, we can see that now in the Program
class, we can add services to the service collection right below the comment that states exactly that. In .NET 5, we would have to do this in the ConfigureServices()
method. Also, we have a section (also marked with a comment) where we can add different middleware components to the application’s pipeline. In .NET 5, we had the Configure()
method for this purpose.
Creating Extension Methods
An extension method is inherently the static method. They play a great role in .NET 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 that 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 { } }
CORS Configuration
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 that allows requests from any source, we could use the WithOrigins("http://www.something.com")
method that will allow requests just from the specified source. Also, instead of AllowAnyMethod()
allowing all HTTP methods, we can use WithMethods("POST", "GET")
one 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 Configuration
Additionally, we need to configure an IIS integration that will help us with the IIS deployment. So, let’s modify the ServiceExtensions
class:
public static void ConfigureIISIntegration(this IServiceCollection services) { services.Configure<IISOptions>(options => { }); }
We do not initialize any properties inside the options because we are fine with the default values. For more information about those properties, let’s check out the details:
To call these extension methods, we are going to modify the Program
class:
using AccountOwnerServer.Extensions; using Microsoft.AspNetCore.HttpOverrides; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.ConfigureCors(); builder.Services.ConfigureIISIntegration(); builder.Services.AddControllers(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) app.UseDeveloperExceptionPage(); else app.UseHsts(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.All }); app.UseCors("CorsPolicy"); app.UseAuthorization(); app.MapControllers(); app.Run();
In the first part, CORS, and IIS configuration have been added. Furthermore, the CORS configuration has been added to the application’s pipeline inside the second part of the class reserved for adding components to a pipeline. The important thing to notice here is that we call the UseCors()
method above the UseAuthorization()
method.
This is the best practice, that Microsoft recommends.
As you may have noticed, there is more code:
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.
Startup Class for .NET 5
If you are using .NET 5, 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.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.All }); app.UseRouting(); app.UseCors("CorsPolicy"); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
Conclusion
Concerning the .NET configuration, we could say that this is quite enough. Now you know how to modify the launchSetting.json file, the purpose of the Program class, how to configure services, and finally how to create and use extension methods.
Thank you for reading and do check out the next part in which we will create our first service, logger service, and use it for logging our messages.
How to configure Cors in .net 6
I don’t understand? This example is .NET 6, so do it exactly as it is shown in the article.
HI, I like your book on Ultimate Asp.net cor Web Api.
it’s very readable and straight to the point. the content is excellent and up to date.
I would like to know if a similar book will be released for Blazor web assembly or server
Hello Samuel. Thanks for the kind words. Since we already have a video course on Blazor WASM, I am not sure that we are going to create a book on the same topic. That said, I see you’ve used blazor discount to purchase the book, which means that you already have the video course. Is there something not fitting your needs inside the course when you are asking for the book on the same topic?
I got an error in Startup.cs.Please Solve This Problem.
I don’t see the entire code, but based on the error message, you are creating an extension method in nonstatic class, and that is not allowed.
I got an other error that is shown in the attached Image.
Thanks, Brother These Problems are solved.But I got an error in Startup.cs class. on Startup.
I got an error that is shown in the attached Image.
Well, your method is outside of the static class. It has to be inside. That’s why we have provided our source code so you can always compare it. It is a quicker way of solving problems rather than waiting for us to reply since sometimes we can’t reply right away.
Done Sir, Thanks a Lot.
Hello, I got an Error in ServicesExtension.cs on ConfigureCors and ConfigureIISIntegration.
public static void ConfigureCors(this IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(“CorsPolicy”,
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
}
public static void ConfigureIISIntegration(this IServiceCollection services)
{
services.Configure<IISOptions>(options =>
{
});
}
.And Also I got an error when adding services.ConfigureCors(); and services.ConfigureIISIntegration(); to startup.cs
“Error CS7036 There is no argument given that corresponds to the required formal parameter”.
Thanks
/Danny
Hi, I have a problem with my project. I have written ConfigureCors according to you but there is nothing in Developer Tools->Network->Response Headers.
Thank you for your answer.
Hello Pavel. When configuring CORS you are allowing your client apps that are hosted on different URI to access your API. Since we consume this API with an Angular app that runs on different URI, we had to enable it. You can read more about CORS here: https://code-maze.com/enabling-cors-in-asp-net-core/
Hi
Do you have source codes on ASP.NET Core Web Api that I can download? It would be easier to read through your article with complete source codes.
Thanks for your great article – they answer lots of my questions confused me before!
Peter
https://github.com/CodeMazeBlog/.NET-Core-Series It is strange that we didn’t link it here. We did that though for the next article.
For IServiceCollection to be found, you need to add the following using-directive:
Perhaps it would be useful to mention it somewhere in the article? I’m very confused how nobody has stumbled upon any errors relating to this, 🤔
Or actually, maybe my editor was just being weird. After I tried removing the using-directive and hovering over IServiceCollection again, it actually suggested I add the using-directive. It didn’t do that at first.
Hello, Zero. Well, this is the main reason why we don’t specify using statements in our code samples. IDE should give you that option right away. When there is a need for specifying the using statement, we do that in the explanation.
thanks for the thorough explanations, great post!
You are very welcome. I hope you will find helpful the rest of the series as well.
I’m looking forward to going through all these posts you’ve written. Do you happen to have anything on web development, css styling in particular?
No, sorry. I have to stick to what I know the best 🙂
Np, thanks 🙂
My copy is saying I need to do something with the Startup class in Startup.cs. Says it must be defined as a non-generic static class but when I change to ‘public static class Startup’ then I get other errors on the page.
Never mind. I just backed everything out and tried again and it seems to be fine.
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.
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.
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?
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.
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.
Perfect !
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.
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
looks like there isn’t part 2 available anymore on the provided github repo link
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.
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. 🙂