Before we start the deployment process, we would like to point out one important thing. We should always deploy an application in the production environment as soon as we start with development. That way we are able to observe how the application behaves in a production environment from the beginning of the development process.
That leads us to the conclusion that the deployment process should not be the last step of the application’s lifecycle. We should deploy our application to the staging environment as soon as we start building it.
For the purpose of this deployment, we are going to build our Angular application for production to produce optimized static files and to combine them with the .NET Core server.
This process is pretty much the same for any client-side project you want (React, Vue.js, or any other).
So, let’s start.
For the complete navigation and all the basic instructions of the Angular series, check out: Introduction of the Angular series.
Let’s start
Building Angular Production Files
First, we need to create the production files for our Angular project by executing publish command:
ng build
This is the way to create the production files for the Angular project. But if we were to use React or Vue.js for the client-side, the command would be:npm run build
:
Initial Chunk Files | Names | Raw Size | Estimated Transfer Size main.8d06eac460cfb2ee.js | main | 594.60 kB | 141.63 kB styles.1167dc02a4a3b18f.css | styles | 175.44 kB | 19.49 kB polyfills.e3ea17d938d5ba3a.js | polyfills | 33.04 kB | 10.59 kB runtime.b5d59dc9d79c9787.js | runtime | 1.22 kB | 655 bytes | Initial Total | 804.31 kB | 172.35 kB
We can see all the published files.
Publishing .NET Core Files for the IIS Deployment
Before we publish our files to the required location, we have to modify our .NET Core app configuration a bit:
var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) app.UseDeveloperExceptionPage(); else { app.Use(async (context, next) => { await next(); if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) { context.Request.Path = "/index.html"; await next(); } }); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles();
If we don’t modify our configuration like this, we won’t be able to start our deployed application at all (as soon as we type the required URL address). But with it, we are safe to continue.
Angular CLI is going to create a new folder with the name “dist” inside our project and publish all the production files inside. Copy all those files from the dist/account-owner-client
folder and paste them into the wwwroot
folder inside the .NET Core’s main project. Now with the static files in the right place, we are going to use Visual Studio’s feature to create publish files for the entire application.
Let’s create a folder on the local machine with the name Publish
. Inside that folder, we want to place all of our files for deployment. Then, right-click on the AccountOwnerServer
project and click the Publish
option:
In the next window, we are going to pick a Folder as the publish target, choose the place where we want to publish our files, and click Finish.
In the next window, we should just click the Publish button.
Now we have all the files in the right place.
Windows Server Hosting Bundle and the Hosts File
Prior to any further action, let’s install .NET Core Windows Server Hosting bundle (we use x64) on our system to install the .NET Core Runtime. Furthermore, with this bundle, we are installing the .NET Core Library and the ASP.NET Core Module. This installation will create a reverse proxy between IIS and the Kestrel server, which is crucial for the deployment process.
During the installation, it will try to install the Microsoft Visual C++ 2015 Redistributable, so just let it do that.
If you have a problem with missing SDK after installing Hosting Bundle, follow this solution suggested by Microsoft:
Installing the .NET Core Hosting Bundle modifies the PATH
when it installs the .NET Core runtime to point to the 32-bit (x86) version of .NET Core (C:\Program Files (x86)\dotnet\
). This can result in missing SDKs when the 32-bit (x86) .NET Core dotnet
command is used (No .NET Core SDKs were detected). To resolve this problem, move C:\Program Files\dotnet\
to a position before C:\Program Files (x86)\dotnet\
on the PATH
environment variable.
After the installation, locate the Windows hosts file on C:\Windows\System32\drivers\etc
and add the a new record at the end of the file:
127.0.0.1 www.accountowner.com
Finally, save the file.
Installing IIS and the Site Deployment
If you don’t have IIS installed on the machine, you need to install it by opening ControlPanel
and then Programs and Features
:
After the IIS installation finishes, open the Run window (windows key + R) and type: inetmgr
to open the IIS manager:
Now we can create a new website:
In the next window we need to add a name to our site and a path to the published files:
After this step, we are going to have our site inside the sites
folder in the IIS Manager. Additionally, we need to set up some basic settings for our application pool:
After we click on the Basic Settings link, let’s configure our application pool:
Your website and the application pool should be started automatically.
In order to deploy the application to IIS, we need to register the IIS integration in our .NET Core part of the project. We have already done that in our ServiceExtensions class, in Part 2 of this tutorial.
Excellent.
Everything is in place.
Now let’s open a browser and type http://www.accountowner.com to inspect the result:
Note: If you get an IIS error “cannot read configuration file due to insufficient permissions”, all you have to do is to add permissions to the Publish
folder to the IIS_IUSRS user. To do that, we have to right-click on the Publish
folder, choose properties, select the Security
tab, click Edit
, then Add
, and add our new user with all the required permissions.
Also, if we navigate to the Owner Actions menu item, we will see all the records displayed.
Conclusion
By reading this post you have learned:
- How to build production files from the client-side application
- The way to publish files by using Visual Studio
- Which additional resources do we need for IIS deployment to work
- How to install IIS
- To deploy the application on IIS
Thank you for reading the post, hopefully, it was helpful to you.
In the next part of the series, we are going to publish this complete application to the Linux environment.
hi i followed all of your steps as you said but when i open my website in chrome is get a this site cant be reached with no additional information any idea what could be causing the problem or how i can solve it
I can’t be sure what is going on there. Are you sure that IIS started the app once the deployment was done? I used this exact tutorial for our Web API book, and everything works great there.
Hi Marinko, When I tried deploying it in default website by clicking add application(on default sie) then angular application is not rendering. but if I do like add website from sites it is working(like the way you mentioned).
But when I deployed my application like new site in remote desktop and trying to access it through my machine it is not working but if it is deployed in default site it is working
1) Is there any thing to be configured in iis for new website
2) is there a way to add configuration file in angular to add api url if I have different servers.
Hello there.
To be honest, I am not sure about the first question.
About the second – you can use environment files to declare URIs as we did in our Angular Environement article in this series.
Try to access the site by PCURL:Port if you are on a different machine on the network. When you are on the deployment server you are looking via local host, but on a different PC you need the specify the IP it exists on. Please check out this: https://stackoverflow.com/questions/21896534/accessing-a-local-website-from-another-computer-inside-the-local-network-in-iis
Hi, one question after deploying my app into IIS I will be having same urls for both api and frontend right? and one more question if we have email service in our application should we configure anything in IIS or we need change any code for that ?
https://code-maze.com/angular-email-confirmation-aspnet-identity/
and how to make clientURI editable in UserForRegistrationDto.
sorry, if I am bothering you
If you use this technique that I’ve explained in this article, you will have the client URI the one that you added in the environment.prod file (in the Angular project), and angular will call the same API URI. I am not sure about your second question, to be honest, I don’t know if you have to configure anything in IIS.
Lastly, to make that clientUri property editable on the client side, you can use the environment file as we did in this series. The API endpoint is the same, just the HTTP part should be changed. Again check the Environment article from this series.
Thanks Marinko, your response means a lot to me. Actually when I deployed my app in IIS everything is working fine but in reset password and confirmation part I am getting internal server error and not receiving email but when I run in development it is working
The best way to see what is going on is to add more logs in your app. That way you can inspect the error and find the cause of the issue. Of course, use global error handler or wrap your actions in try catch block, and log the error, not just the error message, to have all the details of the issue.
Thank you Marinko
Great guide, used this to deploy and worked well. Easy to follow.
Thank you Matt. I’m glad to hear that.
Hi, I would like to have a playlist where I can start with ASP .NET Core API with Angular from start to end with CRUD, Models, Entities, DTO Mapping, JWT, Authentication, Role-based, password reset, unlocking, etc. in a single flow. Thank you.
Thank you very much for your great articles.
Is it possible for you to learn how can be deployed/published a web application (asp.net core 3.x) on Microsoft Azure?
Hi Mainko, Thank you for article, I build the solution on local and runs fine, but when deploying to Azure WebApps it’s failing with the following error:
2019-09-24 22:03:09.413 +00:00 [Critical] Microsoft.AspNetCore.Hosting.Internal.WebHost: Application startup exception
System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)at System.Runtime.Loader.AssemblyLoadContext.InternalLoadUnmanagedDllFromPath(String unmanagedDllPath)at System.Runtime.Loader.AssemblyLoadContext.LoadUnmanagedDllFromPath(String unmanagedDllPath)at PDF_Generator.Startup.ConfigureServices(IServiceCollection services) in C:Userspaalexansourcereposcreate-pdf-with-netcore-masterPDF_GeneratorPDF_GeneratorStartup.cs:line 34— End of stack trace from previous location where exception was thrown —at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()at Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()— End of stack trace from previous location where exception was thrown —at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
Do you have any guidelines on how to deploy this API to Azure ?
Hello Patrick. We don’t have any article on that subject and I am not that much familiar with Azure deploying actions. If you find the solution, it would be great if you could share it with us here, of course if you find some free time to do that. Best regards.
Hello Marinko, Vladimir. I almost managed to deploy my App on IIS. The login page opens, but when I try to log in I get this:
polyfills-es2015.f5cf985d419cf8769fae.js:1 OPTIONS http://localhost:5000/api/auth/login net::ERR_CONNECTION_REFUSED.
Ports remained: client :4200 and server :5000, as it was during development.
I found and tried a lot of recommendations on how to solve the problem, but still can not.
If your piblished app tries to run on localhost, than probably something is wrong with the environment files setup. Have you checked that? After you create an Angular publish files, can you find in the main… file your prodiction address?
Thank you, Marinko, I’m already studying part 9 of the tutorial
Hello, Marinko. Thanks for the great information, very useful especially for a newcomer like me. Is it possible to deploy a site without a domain name, only an IP address?
Hello Vasily. Let me say this way, every public site has an IP address behind its fomain name and you can always browse it by typing that IP address. But you have to use domain name to be able to deploy your app on any public server.
Thank you, I see about the domain. I mean using the ip only for testing on server. Is it possible to use ip temporarily when filling the Site name field?
Hey Vasily, every machine has an IP address, and you can access your website through port 80 for example through IP address. (eg http://11.22.33.44:80)
It is strongly advised to use domain names though, since that way you can do some nifty things like create as many subdomains and set up SSL certs to secure your website traffic. You can also host multiple websites that way and have only port 80 and 443 open (HTTP and HTTPS). The webserver can decide which request goes to which website then.
Hope this answers your questions.
I suggest you play around a bit with these concepts by trying to host your website on AWS or Azure or anywhere else and see how these concepts work in practice. (On your own machine ofc)
Thank you, Vladimir, that’s what I wanted to know. In the near future there will be access to the domain name and I will be able to use it
Great, good luck!
Hi, great tutorial. Just one question. While deploying the app to ISS, when you are ultimately putting all your Angular frontend compiled code in the .NET project itself ( inside www folder ). Then why there is a need to implement CORS functionality that you explained earlier in part 2 under “Basic Code Preparations”.
Here is the link – http://34.65.74.140/net-core-web-development-part2/#extension
Hello Hitesh. Well you have to develop your project prior to publishing it. And if your server runs on :5000 and your client on :4200 port, there is no way to provide communication between them without the CORS implementation.
Hi, great tutorial. I have one question. you know how I could do the deployment of the same application but in a hosting like GoDaddy??
and an apology, that my English is not very good
Regards!.
Hello David. There is no need to apologize, the question is clear enough 😀 About the hosting, it depends whether you want IIS or Linux hosting. For the Linux hosting, you have our article about Linux deployment, so all you need to do is to find yourself some cheep hosting server (just to start with something) and to follow the guide from our article. If you want IIS hosting, just search on Google for “IIS Hosting .NET Core trial” and you will find one that will give you free 60 days trial period. It is very easy to deploy your app there. Just build your files, transfer them to their server and that should be it (maybe couple more of small changes, I can’t remember). Then you can even buy a domain from GoDaddy if you like and attach it to your site. You have all the instructions on their site as well.
I understand and congratulations …
It’s the best tutorial I’ve seen about ASP.NET Core Web API
Thank you!
Great article, Found lot of stuff useful.
May you please share link of Deployment process of .NET Core Api and Angular project in Linux environment?
Hello mate. On this link you will find required article: http://34.65.74.140/net-core-web-development-part17/
Thank you very much for reading.
All the best.
Hi Marinko, hope you are well.
I’m getting a “HTTP Error 500.19 – Internal Server Error” when browsing http://www.accountowner.com.
The error code is 0x8007000d which, according to Microsoft (https://support.microsoft.com/en-us/help/942055/http-error-500-19-error-when-you-open-an-iis-7-0-webpage) it means a malformed XML element in the web.config file. Could you take a look, please? My web.config file is as follows, after publishing:
Also, some interesting parts of the error:
Module IIS Web Core
Notification Unknown
Handler Not yet determined
Error Code 0x8007000d
Config Error
Config File \?C:[mypath]AccountOwnerweb.config
Requested URL http://www.accountowner.com:80/
Physical Path
Logon Method Not yet determined
Logon User Not yet determined
I have tried a bunch of “google fixes” but nothing worked. Hope you can help.
Regards!
Hello Caio Castro, I am fine, thank you for asking. I am sorry to see you having trouble deploying your application, but I need to ask you some questions. Where did you find the web.config file? And what type of application you are trying to deploy? In .NET Core’s apps you don’t have web.config but appconfig.json file. Did you give all the rights (read, write…) to your applicationpool user for the folder where your published files resides? Maybe IIS can’t access web.config file inside it?
I had the same issue, the reason for that was that I omitted “Windows Server Hosting Bundle…” step, the solution is to download and install DotNetCore.2.0.5-WindowsHosting.exe.
After that it worked just fine.
Thank you very much for the help. Yes it is very important tho install Hosting Bundle. But to admit I didn’t know what kind of error will it rise if not installed. Now I know. You are awesome mate.
ok! Finally got it! (ish).
1. I actually had installed the “Windows server hosting bundle” the first time, but the installer failed to go through the Microsoft Visual C++ 2015 Redistributable. I believe this is because I already had installed the c++ 2017 package. I manually uninstalled c++ 2017, and then reinstalled c++ 2015 and c++2017.
2. Moving along, I was getting an authentication error as the Anonymous Authentication user (IUSR) couldn’t read the files, even though I expressly gave all authorizations required. Go figure… So, when adding a webserver in the IIS Manager, I changed the “Connect As” configuration from “application user” to “specific user” and typed in my user credentials. Tested and all files were readable now.
3. Went straight to browsing to get a “page not found” error. This turned out to be sloppiness from my part. When in the blog post you mentioned “Copy all those files from the dist folder and paste them into the wwwroot folder”, I thought “well, just pasting the entire dist folder with the files inside should do the trick”. I guess I was wrong, hehe. I just took the files out of the dist folder and straight to the wwwroot folder and FINALLY got to see my beautiful accountowner webpage up and running.
It’s just the authentication error that is boggling me right now, but since I finally got deployment through, I guess I’ll just leave it like that for the moment.
Marinko and irrelevant, thanks for the comments. It really helped to focus where to look for the errors.
And again, awesome job with this series.