{"id":657,"date":"2019-05-27T20:13:14","date_gmt":"2019-05-28T00:13:14","guid":{"rendered":"http:\/\/salzlechner.com\/dev\/?p=657"},"modified":"2019-08-10T11:57:01","modified_gmt":"2019-08-10T15:57:01","slug":"net-core-web-api-part-1","status":"publish","type":"post","link":"http:\/\/salzlechner.com\/dev\/2019\/05\/27\/net-core-web-api-part-1\/","title":{"rendered":".NET Core Web API &#8211; Part 1"},"content":{"rendered":"<p>In this multi part blog post we will be creating a .NET Core based Web API with authentication and a number of other features.<\/p>\n<p>To start we will create a new project in Visual Studio by selecting the ASP.NET Core Web Application project type<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-658\" src=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2019\/05\/netcore1.png\" alt=\"\" width=\"492\" height=\"256\" srcset=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2019\/05\/netcore1.png 1093w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2019\/05\/netcore1-300x156.png 300w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2019\/05\/netcore1-768x400.png 768w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2019\/05\/netcore1-1024x533.png 1024w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2019\/05\/netcore1-1080x562.png 1080w\" sizes=\"(max-width: 492px) 100vw, 492px\" \/><\/p>\n<p>then we select the API option on the next dialog<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-659\" src=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2019\/05\/dotnetcore2.png\" alt=\"\" width=\"481\" height=\"338\" srcset=\"http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2019\/05\/dotnetcore2.png 1180w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2019\/05\/dotnetcore2-300x211.png 300w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2019\/05\/dotnetcore2-768x540.png 768w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2019\/05\/dotnetcore2-1024x720.png 1024w, http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2019\/05\/dotnetcore2-1080x760.png 1080w\" sizes=\"(max-width: 481px) 100vw, 481px\" \/><\/p>\n<p>In this example we want to first implement authentication with a standard user and role table in our own database.<\/p>\n<p>That is not an option in the template so we simply select &#8216;No Authentication&#8217; and add it later on.<\/p>\n<p>Click the OK button and wait for Visual Studio to create our base project. This will create a simple base web API with a sample values controller.<\/p>\n<p>First thing we need to do is to configure the database connection. Add your connection string to the appsettings.json file<\/p>\n<pre class=\"lang:default decode:true\">\"ConnectionStrings\": { \"DefaultConnection\": \"Server=SERVER\\\\INSTANCE;Database=DOTNETCORESAMPLE;Trusted_Connection=True;MultipleActiveResultSets=true\" },<\/pre>\n<p>We also need to create a database context and register the context with the application<\/p>\n<pre class=\"lang:c# decode:true \">\/\/ \npublic class ApplicationDbContext : IdentityDbContext&lt;IdentityUser&gt;\n{\n    public ApplicationDbContext(DbContextOptions&lt;ApplicationDbContext&gt; options)\n        : base(options)\n    {\n    }\n\n}\n<\/pre>\n<p>then in Startup.cs add the following to add the ApplicationDbContext<\/p>\n<pre class=\"lang:default decode:true \">\/\/\nservices.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;\n                options.UseSqlServer(\n                    Configuration.GetConnectionString(\"DefaultConnection\")));<\/pre>\n<p>To create the base ASP.Net authentication tables in our database execute the following line in the console<\/p>\n<pre class=\"lang:default decode:true\"> Add-Migration InitialCreate<\/pre>\n<p>this will create the migration steps for the initial creation of the authentication tables<\/p>\n<p>now execute the following to run the migration<\/p>\n<pre class=\"lang:default decode:true\">update-database<\/pre>\n<p>this will create all the tables in your database needed for authentication<\/p>\n<p>In order to be able to extend the user table with additional fields we will create a model for our ApplicationUser<\/p>\n<pre class=\"lang:default decode:true\">\/\/\npublic class ApplicationUser : IdentityUser\n{\n    \/\/ Extended Properties\n   \n}\n<\/pre>\n<p>And of course we have to change all the references we have to IdenityUser to refer to the ApplicationUser instead.<\/p>\n<p>Now we need to configure the project for identity and authentication<\/p>\n<p>add the following code to the ConfigureServices method in StartUp to add the IdentoryService<\/p>\n<pre class=\"lang:default decode:true\">services.AddIdentity&lt;ApplicationUser, IdentityRole&gt;()\n    .AddEntityFrameworkStores&lt;ApplicationDbContext&gt;()\n    .AddDefaultTokenProviders();\n<\/pre>\n<p>then also in ConfigureServices we add the following to configure the IdentityOptions<\/p>\n<pre class=\"lang:default decode:true \">services.Configure&lt;IdentityOptions&gt;(options =&gt;\n{\n    \/\/ Password settings.\n    options.Password.RequireDigit = true;\n    options.Password.RequireLowercase = true;\n    options.Password.RequireNonAlphanumeric = true;\n    options.Password.RequireUppercase = true;\n    options.Password.RequiredLength = 6;\n    options.Password.RequiredUniqueChars = 1;\n\n    \/\/ Lockout settings.\n    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);\n    options.Lockout.MaxFailedAccessAttempts = 5;\n    options.Lockout.AllowedForNewUsers = true;\n\n    \/\/ User settings.\n    options.User.AllowedUserNameCharacters =\n    \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+\";\n    options.User.RequireUniqueEmail = true;\n\n\n});\n<\/pre>\n<p>and one more to configure the ApplicationCookie options<\/p>\n<pre class=\"lang:default decode:true \">services.ConfigureApplicationCookie(options =&gt;\n{\n    \/\/ Cookie settings\n    options.Cookie.HttpOnly = true;\n    options.ExpireTimeSpan = TimeSpan.FromMinutes(5);\n\n    options.LoginPath = \"\/Identity\/Account\/Login\";\n    options.AccessDeniedPath = \"\/Identity\/Account\/AccessDenied\";\n    options.SlidingExpiration = true;\n\n    options.Events.OnRedirectToLogin = context =&gt;\n    {\n        if (context.Request.Path.StartsWithSegments(\"\/api\") &amp;&amp;\n            context.Response.StatusCode == (int)HttpStatusCode.OK)\n        {\n            context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;\n        }\n        else\n        {\n            context.Response.Redirect(context.RedirectUri);\n        }\n        return Task.FromResult(0);\n\n        \/\/context.Response.StatusCode = 401;\n        \/\/return Task.CompletedTask;\n    };\n});\n<\/pre>\n<p>Next step is to make sure we have some default roles and a default user in our database. To do this we can add code to seed the database with our defaults<\/p>\n<p>Then we add the following line to the Configure method<\/p>\n<pre class=\"lang:default decode:true\">app.UseAuthentication();<\/pre>\n<p>Lets create a class called SeedDataManager as follows<\/p>\n<pre class=\"lang:default decode:true\">\/\/\npublic static class SeedDataManager\n    {\n        public static void SeedData\n            (UserManager&lt;ApplicationUser&gt; userManager,\n            RoleManager&lt;IdentityRole&gt; roleManager)\n        {\n            SeedRoles(roleManager);\n            SeedUsers(userManager);\n        }\n\n        public static void SeedUsers\n            (UserManager&lt;ApplicationUser&gt; userManager)\n        {\n        }\n\n        public static void SeedRoles\n            (RoleManager&lt;IdentityRole&gt; roleManager)\n        {\n        }\n    }<\/pre>\n<p>We can call the SeedData method from the configure method in Startup<\/p>\n<pre class=\"lang:default decode:true\">public void Configure(IApplicationBuilder app, IHostingEnvironment env, \n            UserManager&lt;ApplicationUser&gt; userManager,\n            RoleManager&lt;IdentityRole&gt; roleManager)\n{\n    ....\n\n    SeedDataHelper.SeedData(userManager, roleManager);\n\n    \n}<\/pre>\n<p>We use Dependency Injection to injext the UserManager as well as the RoleManager, then call our SeedData method.<\/p>\n<p>Now lets take a look at seeding the role table. For our example lets create a role called &#8216;User&#8217; and another role called &#8216;Administrator&#8217;<\/p>\n<pre class=\"lang:default decode:true \">public static void SeedRoles\n    (RoleManager&lt;IdentityRole&gt; roleManager)\n{\n    if (!roleManager.RoleExistsAsync\n        (\"User\").Result)\n    {\n        IdentityRole role = new IdentityRole();\n        role.Name = \"User\";\n        \n        IdentityResult roleResult = roleManager.\n        CreateAsync(role).Result;\n    }\n\n\n    if (!roleManager.RoleExistsAsync\n        (\"Administrator\").Result)\n    {\n        IdentityRole role = new IdentityRole();\n        role.Name = \"Administrator\";\n\n        IdentityResult roleResult = roleManager.\n        CreateAsync(role).Result;\n    }\n}\n<\/pre>\n<p>and then we also create an admin user<\/p>\n<pre class=\"lang:default decode:true\">public static void SeedUsers\n    (UserManager&lt;ApplicationUser&gt; userManager)\n{\n    if (userManager.FindByNameAsync(\"admin@localhost\").Result == null)\n    {\n        ApplicationUser user = new ApplicationUser();\n        user.UserName = \"admin@localhost\";\n        user.Email = \"admin@localhost\";\n\n        IdentityResult result = userManager.CreateAsync\n        (user, \"Admin!1234\").Result;\n\n        if (result.Succeeded)\n        {\n            userManager.AddToRoleAsync(user,\n                                \"Administrator\").Wait();\n        }\n    }\n\n}\n<\/pre>\n<p>next time you run the project the system will create the two roles as well as our default admin user<\/p>\n<p>to test the authentication we can add another endpoint to the values controller as follows<\/p>\n<pre class=\"lang:default decode:true \">\/\/\n[HttpGet]\n[Route(\"GetAuthorized\")]\n[Authorize]\npublic ActionResult&lt;IEnumerable&lt;string&gt;&gt; GetAuthorized()\n{\n    return new string[] { \"value1\", \"value2\" };\n}\n\n<\/pre>\n<p>calling the following endpoint<\/p>\n<pre class=\"lang:default decode:true\">https:\/\/localhost:44307\/api\/values<\/pre>\n<p>should return the following data<\/p>\n<pre class=\"lang:default decode:true\">[\"value1\",\"value2\"]<\/pre>\n<p>calling the new end point decorated with Authorize will return an HTTP status code of 401 because we are not authenticated<\/p>\n<pre class=\"lang:default decode:true\">https:\/\/localhost:44307\/api\/values\/GetAuthorized<\/pre>\n<p>In Part 2 we will add an endpoint to authenticate a user with our web api<\/p>\n\n\t\t<div class='author-shortcodes'>\n\t\t\t<div class='author-inner'>\n\t\t\t\t<div class='author-image'>\n\t\t\t<img src='http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2016\/02\/mike5crop-566174_60x60.jpg' alt='' \/>\n\t\t\t<div class='author-overlay'><\/div>\n\t\t<\/div> \n\t\t<div class='author-info'>\n\t\t\tMichael Salzlechner is the CEO of StarZen Technologies, Inc.<\/p>\n<p>He was part of the Windows Team at Data Access Worldwide that created the DataFlex for Windows Product before joining&nbsp;<a href=\"http:\/\/starzen.com\">StarZen Technologies<\/a>. StarZen Technologies provides consulting services as well as custom Application development and third party products<\/p>\n\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/div>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this multi part blog post we will be creating a .NET Core based Web API with authentication and a number of other features. To start we will create a new project in Visual Studio by selecting the ASP.NET Core Web Application project type then we select the API option on the next dialog In [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":735,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","ngg_post_thumbnail":0,"footnotes":""},"categories":[42,7,4],"tags":[43,44,45,46],"class_list":["post-657","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-core","category-c","category-windows","tag-net","tag-net-core","tag-c","tag-web-api"],"_links":{"self":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/657","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/comments?post=657"}],"version-history":[{"count":6,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/657\/revisions"}],"predecessor-version":[{"id":734,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/657\/revisions\/734"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/media\/735"}],"wp:attachment":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/media?parent=657"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/categories?post=657"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/tags?post=657"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}