Quantcast
Channel: All About ASP.NET and ASP.NET Core 2 Hosting BLOG
Viewing all 427 articles
Browse latest View live

ASP.NET Core Hosting :: How to Create CRUD App Using Blazor and ASP.NET Core

$
0
0

Blazor is an experimental .NET web framework using C#/Razor and HTML that runs in the browser via WebAssembly. It simplifies the process of creating single page application (SPA) and at the same time also brings the power of .NET on the table. It runs in the browser on a real .NET runtime (Mono) implemented in WebAssembly that executes normal .NET assemblies. In this post, we’ll see how to set up blazor and create a CRUD app using blazor and ASP.NET Core.

Creating a Blazor App

To create a blazor app, open Visual Studio 2017 “Preview” version, hit Ctrl+Shift+N and select the ASP.NET Core Web Application (.NET Core) project type from the templates. When you click Ok, you will get the following prompt,

If you don’t see these blazor templates, make sure .NET Core and ASP.NET Core 2.0 are selected at the top. As you can see, there are 2 blazor templates. The standalone “Blazor” template will create a static blazor app and “Blazor (ASP.NET Core Hosted)” will create an ASP.NET Core hosted blazor app. Choose “Blazor (ASP.NET Core Hosted)” to create the blazor app. Now, our first Blazor app will be created. In the solution explorer, you will find 3 projects created.

  • <Project Name>.Client: Standard blazor application.
  • <Project Name>.Server: It’s an ASP.NET Core Web API project.
  • <Project Name>.Shared: It’s a .NET standard class library project used for holding the shared resources.

You should run the app to make sure that there are no errors. Press Ctrl-F5 to run the app without the debugger. Running with the debugger (F5) is not supported at this time. Next thing is to extend this app to create a CRUD app.

Create the CRUD App

Before we move on, take a look at the following image to get an idea of what we are building.

As you can see, we are building a ToDo List app supporting all the CRUD operations and a listing of the ToDo items. We’ll use Entity Framework Core in-memory provider to store the ToDo list. So let’s begin.

First, create a ToDoList class in the Shared project with the following code. It’s a simple class with only two members.

public class ToDoList
{
    public int ID { get; set; }

    public string Item { get; set; }
}

Next, create EF DBContext to interact with the database. To do that, create a new folder named “Data” in the Server project. Add a new class file named ToDoListContext with the following code.

public class ToDoListContext : DbContext
{
    public ToDoListContext(DbContextOptions<ToDoListContext> options) : base(options) { }

    public DbSet<ToDoList> ToDoLists { get; set; }
}

We’ll need to configure InMemory db provider. To do that, Open Startup.cs class and navigate to the ConfigureServices method to configure it (Line no. 4).

public void ConfigureServices(IServiceCollection services)
{
    // Use Entity Framework in-memory provider for this sample
    services.AddDbContext<ToDoListContext>(options => options.UseInMemoryDatabase("ToDoList"));

    services.AddMvc().AddJsonOptions(options =>
    {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });

    services.AddResponseCompression(options =>
    {
        options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
        {
            MediaTypeNames.Application.Octet,
            WasmMediaTypeNames.Application.Wasm,
        });
    });
}

Next, we’ll need an API controller for all CRUD operations. To do that, create a new controller named ToDoListController inside the Controller folder in the Server project with the following code.

[Produces("application/json")]
[Route("api/ToDo")]
public class ToDoListController : Controller
{
    private readonly ToDoListContext _context;

    public ToDoListController(ToDoListContext context)
    {
        _context = context;
    }

    // GET: api/ToDo
    [HttpGet]
    public IEnumerable<ToDoList> GetToDo()
    {
        return _context.ToDoLists;
    }

    // POST: api/ToDo
    [HttpPost]
    public async Task<IActionResult> PostToDo([FromBody] ToDoList todo)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        _context.ToDoLists.Add(todo);
        await _context.SaveChangesAsync();
        return CreatedAtAction("GetToDo", new { id = todo.ID }, todo);
    }

    // PUT: api/ToDo/5
    [HttpPut("{id}")]
    public async Task<IActionResult> PutToDo([FromRoute] int id, [FromBody] ToDoList todo)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        if (id != todo.ID)
            return BadRequest();

        _context.Entry(todo).State = EntityState.Modified;
        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!ToDoExists(id))
                return NotFound();
            else
                throw;
        }
        return NoContent();
    }

    // DELETE: api/ToDo/5
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteToDo([FromRoute] int id)
    {
        var ToDo = await _context.ToDoLists.SingleOrDefaultAsync(m => m.ID == id);
        if (ToDo == null)
            return NotFound();

        _context.ToDoLists.Remove(ToDo);
        await _context.SaveChangesAsync();
        return Ok(ToDo);
    }

    private bool ToDoExists(int id)
    {
        return _context.ToDoLists.Any(e => e.ID == id);
    }
}

Here, the controller has API for all CRUD operations with proper validations. Quite familiar piece of code, isn’t it?

Blazor App Code

Next, we need to add the ToDo component to the Client App. The default app is already having Home, Counter and Fetch Data component. To add ToDo component, right-click on Pages folder and select Add > New Item. Select Web from the left panel, then select “Razor View” from templates panel and name it ToDo.cshtml. Put the following code in the file.

@page "/todo"
@using ASPNETBlazorCRUDApp.Shared
@using Microsoft.AspNetCore.Blazor.Browser.Interop
@inject HttpClient Http

<h1>ToDo List</h1>

<div>
    <div class="row">
        <div class="col-sm-1">
            <p>Item:</p>
        </div>
        <div class="col-sm-4">
            <input id="todoName" placeholder="Item Name" @bind(itemName)>
        </div>
    </div>
    <br />
    <div class="row">
        <div class="col-sm-1">
            <button class="btn btn-info" id="btnAdd" @onclick(async () => await AddToDo())>Add</button>
        </div>
        <div class="col-sm-2">
            @if (todos != null && todos.Count > 0)
            {
                <button class="btn btn-danger" @onclick(async () => await DeleteAllToDos())>Delete All</button>
            }
        </div>
    </div>
</div>
<br /><br />
@if (todos == null)
{
    <p><em>Loading...</em></p>
}
else
{
    @if (todos.Count > 0)
    {
        <table class='table table-striped table-bordered table-hover table-condensed' style="width:80%;">
            <thead>
                <tr>
                    <th style="width: 40%">Name</th>
                    <th style="width: 40%">Edit</th>
                    <th style="width: 20%">Delete</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var todo in todos)
                {
                    <tr>
                        <td>
                            <span id="spn_@todo.ID">@todo.Item</span>
                            <input id="txt_@todo.ID" @bind(UpdateItemName) style="display:none;">
                        </td>
                        <td>
                            <button id="btnEdit_@todo.ID" class="btn btn-primary" @onclick(() => EditToDo(todo.ID, todo.Item))>Edit</button>
                            <button id="btnUpdate_@todo.ID" style="display:none;" class="btn btn-success" @onclick(async () => await UpdateToDo(todo.ID))>Update</button>
                            <button id="btnCancel_@todo.ID" style="display:none;" class="btn btn-primary" @onclick(() => CancelToDo(todo.ID))>Cancel</button>
                        </td>
                        <td><button class="btn btn-danger" @onclick(async () => await DeleteToDo(todo.ID))>Delete</button></td>
                    </tr>
                }
            </tbody>
        </table>
    }
}

<script>
    Blazor.registerFunction('ShowControl', (id, item, bShow) => {
        if (bShow) {
            var txtInput = document.getElementById("txt_" + id);
            document.getElementById("spn_" + id).style.display = "none";
            txtInput.style.display = "";
            txtInput.value = item;
            txtInput.focus();
            document.getElementById("btnEdit_" + id).style.display = "none";
            document.getElementById("btnUpdate_" + id).style.display = "";
            document.getElementById("btnCancel_" + id).style.display = "";
        }
        else {
            document.getElementById("spn_" + id).style.display = "";
            document.getElementById("txt_" + id).style.display = "none";
            document.getElementById("btnEdit_" + id).style.display = "";
            document.getElementById("btnUpdate_" + id).style.display = "none";
            document.getElementById("btnCancel_" + id).style.display = "none";
        }
        return true;
    });
</script>
@functions {
        string itemName;
        string UpdateItemName;

        IList<ToDoList> todos = new List<ToDoList>();

protected override async Task OnInitAsync()
    {
        await Refresh();
    }

    private async Task Refresh()
    {
        todos = await Http.GetJsonAsync<ToDoList[]>("/api/ToDo");
        StateHasChanged();
    }

    private async Task AddToDo()
    {
        if (!string.IsNullOrEmpty(itemName))
        {
            await Http.SendJsonAsync(HttpMethod.Post, "/api/ToDo", new ToDoList
            {
                Item = itemName,
            });

            itemName = "";
            await Refresh();
        }
    }

    private async Task UpdateToDo(int id)
    {
        if (!string.IsNullOrEmpty(UpdateItemName))
        {
           await Http.SendJsonAsync(HttpMethod.Put, $"/api/ToDo/{id}", new ToDoList
            {
                ID = id,
                Item = UpdateItemName,
            });

            await Refresh();
            //UpdateItemName = "";

            RegisteredFunction.Invoke<bool>("ShowControl", id.ToString(), "", false);
        }
    }

    private async Task DeleteToDo(int id)
    {
        await Http.DeleteAsync($"/api/ToDo/{id}");
        await Refresh();
    }

    private void EditToDo(int id, string itemName)
    {
        RegisteredFunction.Invoke<bool>("ShowControl", id.ToString(), itemName, true);
    }

    private void CancelToDo(int id)
    {
        RegisteredFunction.Invoke<bool>("ShowControl", id.ToString(), "", false);
    }

    private async Task DeleteAllToDos()
    {
        foreach (var c in todos)
        {
            await Http.DeleteAsync($"/api/ToDo/{c.ID}");
        }

        await Refresh();
    }
}

Let’s understand this code. The above code can be divided into 3 sections (HTML, JavaScript and C#). We’ll take a look at each of them in details. before, we do that, let’s understand the very first 4 lines.

@page "/todo"
@using ASPNETBlazorCRUDApp.Shared
@using Microsoft.AspNetCore.Blazor.Browser.Interop
@inject HttpClient Http

  • We are defining the route for this page using @page directive. So appending “/todo” to base URL will redirect to this component.
  • Including the ASPNETBlazorCRUDApp.Shared namespace as ToDoList class is used.
  • The namespace Microsoft.AspNetCore.Blazor.Browser.Interop is included to call JavaScript from the Blazor code. Currently, WebAssembly and therefore Mono and Blazor have no direct access to the browser’s DOM API. Read this post for a detailed information.
  • We are also injecting HTTPClient dependency to call the server-side API.

Now,let’s understand the each section.

HTML

The HTML part is quite simple if you are familiar with Razor syntax. It has a table and a couple of buttons. The @bind is used for two-way data-binding. Read more about data binding here. The @onclick is used to call the method on the click of the button.

JavaScript

Blazor directly can’t call JavaScript function. From learn-blazor.com

To call other JS libraries or your own custom JS/TS code from .NET, the current approach is to register a named function in a JavaScript/TypeScript file, e.g.:

// This is JavaScript
Blazor.registerFunction('doPrompt', message => {
  return prompt(message);
});

… and then wrap it for calls from .NET:

// This is C#
public static bool DoPrompt(string message)
{
    return RegisteredFunction.Invoke<bool>("doPrompt", message);
} 

The JavaScript function named ShowControl defined in the code, controls the visibility of the HTML elements. This is called from C# code on click of Edit, Update and Cancel button.

C#

At the bottom of the page, there is a @functions section which contains code for making server-side web api call for CRUD operations, calling JavaScript and refreshing the ToDo list. The only new thing here is the way C# makes a call to JavaScript ShowControl function on Edit, Update and Cancel button. Other than that it’s simple and familiar code.

Lastly, we need to add the “ToDo” component link in the navigation bar. To do that, open the NavMenu.html file located inside the Shared folder in the client app and add the following code just after the “Fetch Data” link.

<li>
    <NavLink href="http://dotnet4hosting.asphostportal.com/todo">
        <span class='glyphicon glyphicon-list-alt'></span> To Do
    </NavLink>
</li>

That’s it. Run the application and you should see the following.

 

Final Thoughts

These are still early days for Blazor, but we can start building component-based web apps that run in the browser with .NET. Initially, you would find difficult to make progress. Microsoft has promised to bring many new features and improvements planned for future updates. Let’s hope that soon there will be an official documentation and great community support. In this post, we learned about the new .NET framework – Blazor and also created a simple CRUD application using Blazor.

I am really excited to play with this, so more blog post coming up on Blazor. Thank you for reading. Keep visiting this blog and share this in your network. Please put your thoughts and feedback in the comments section.


ASP.NET Core Hosting :: How to Handle Multipart Request with JSON and File Uploads in ASP.NET Core

$
0
0

Suppose we’re writing an API for a blog. Our "create post" endpoint should receive the title, body, tags and an image to display at the top of the post. This raises a question: how do we send the image? There are at least 3 options:

Embed the image bytes as base64 in the JSON payload, e.g.

{
    "title": "My first blog post",
    "body": "This is going to be the best blog EVER!!!!",
    "tags": [ "first post", "hello" ],
    "image": "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
}

This works fine, but it’s probably not a very good idea to embed an arbitrarily long blob in JSON, because it could use a lot of memory if the image is very large.

Send the JSON and image as separate requests. Easy, but what if we want the image to be mandatory? There’s no guarantee that the client will send the image in a second request, so our post object will be in an invalid state.

Send the JSON and image as a multipart request.

The last approach seems the most appropriate; unfortunately it’s also the most difficult to support… There is no built-in support for this scenario in ASP.NET Core. There is some support for the multipart/form-data content type, though; for instance, we can bind a model to a multipart request body, like this:

public class MyRequestModel
{
    [Required]
    public string Title { get; set; }
    [Required]
    public string Body { get; set; }
    [Required]
    public IFormFile Image { get; set; }


public IActionResult Post([FromForm] MyRequestModel request)
{
    ...
}

But if we do this, it means that each property maps to a different part of the request; we’re completely giving up on JSON.

There’s also a MultipartReader class that we can use to manually decode the request, but it means we have to give up model binding and automatic model validation entirely.

Custom model binder

Ideally, we’d like to have a request model like this:

public class CreatePostRequestModel
{
    [Required]
    public string Title { get; set; }
    [Required]
    public string Body { get; set; }
    public string[] Tags { get; set; }
    [Required]
    public IFormFile Image { get; set; }
}

Where the TitleBody and Tags properties come from a form field containing JSON and the Image property comes from the uploaded file. In other words, the request would look like this:

POST /api/blog/post HTTP/1.1
Content-Type: multipart/form-data; boundary=AaB03x  

--AaB03x
Content-Disposition: form-data; name="json"
Content-Type: application/json  

{
    "title": "My first blog post",
    "body": "This is going to be the best blog EVER!!!!",
    "tags": [ "first post", "hello" ]
}
--AaB03x
Content-Disposition: form-data; name="image"; filename="image.jpg"
Content-Type: image/jpeg  

(... content of the image.jpg file ...)
--AaB03x

Fortunately, ASP.NET Core is very flexible, and we can actually make this work, by writing a custom model binder.

Here it is:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json; 

namespace TestMultipart.ModelBinding
{
    public class JsonWithFilesFormDataModelBinder : IModelBinder
    {
        private readonly IOptions<MvcJsonOptions> _jsonOptions;
        private readonly FormFileModelBinder _formFileModelBinder; 

        public JsonWithFilesFormDataModelBinder(IOptions<MvcJsonOptions> jsonOptions, ILoggerFactory loggerFactory)
        {
            _jsonOptions = jsonOptions;
            _formFileModelBinder = new FormFileModelBinder(loggerFactory);
        } 

        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
                throw new ArgumentNullException(nameof(bindingContext)); 

            // Retrieve the form part containing the JSON
            var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.FieldName);
            if (valueResult == ValueProviderResult.None)
            {
                // The JSON was not found
                var message = bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(bindingContext.FieldName);
                bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, message);
                return;
            } 

            var rawValue = valueResult.FirstValue; 

            // Deserialize the JSON
            var model = JsonConvert.DeserializeObject(rawValue, bindingContext.ModelType, _jsonOptions.Value.SerializerSettings); 

            // Now, bind each of the IFormFile properties from the other form parts
            foreach (var property in bindingContext.ModelMetadata.Properties)
            {
                if (property.ModelType != typeof(IFormFile))
                    continue; 

                var fieldName = property.BinderModelName ?? property.PropertyName;
                var modelName = fieldName;
                var propertyModel = property.PropertyGetter(bindingContext.Model);
                ModelBindingResult propertyResult;
                using (bindingContext.EnterNestedScope(property, fieldName, modelName, propertyModel))
                {
                    await _formFileModelBinder.BindModelAsync(bindingContext);
                    propertyResult = bindingContext.Result;
                } 

                if (propertyResult.IsModelSet)
                {
                    // The IFormFile was sucessfully bound, assign it to the corresponding property of the model
                    property.PropertySetter(model, propertyResult.Model);
                }
                else if (property.IsBindingRequired)
                {
                    var message = property.ModelBindingMessageProvider.MissingBindRequiredValueAccessor(fieldName);
                    bindingContext.ModelState.TryAddModelError(modelName, message);
                }
            } 

            // Set the successfully constructed model as the result of the model binding
            bindingContext.Result = ModelBindingResult.Success(model);
        }


    }
}

To use it, just apply this attribute to the CreatePostRequestModel class above:

[ModelBinder(typeof(JsonWithFilesFormDataModelBinder), Name = "json")]}
public class CreatePostRequestModel

This tells ASP.NET Core to use our custom model binder to bind this class. The Name = "json" part tells our binder from which field of the multipart request it should read the JSON (this is the bindingContext.FieldName in the binder code).

Now we just need to pass a CreatePostRequestModel to our controller action, and we’re done:

[HttpPost]
public ActionResult<Post> CreatePost(CreatePostRequestModel post)
{
    ...
}

This approach enables us to have a clean controller code and keep the benefits of model binding and validation. It messes up the Swagger/OpenAPI model though, but hey, you can’t have everything!

ASP.NET Core 2.2 Hosting :: Feature Flags with ASP.NET Core 2.2

$
0
0

Feature flags can be useful for changing the runtime behavior of an application with minimal impact. Having a UI to toggle the feature flags on and off is extra helpful, too!

That said, we built a library to enable this in a strongly typed fashion! Here’s what the UI looks like:

Installation

Install the RimDev.AspNetCore.FeatureFlags NuGet package.

> dotnet add package RimDev.AspNetCore.FeatureFlags

Or

PM> Install-Package RimDev.AspNetCore.FeatureFlags

Usage

You’ll need to wire up Startup.cs as follows:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using RimDev.AspNetCore.FeatureFlags;

namespace MyApplication
{
    public class Startup
    {
        private static readonly FeatureFlagOptions options = new FeatureFlagOptions()
            .UseCachedSqlFeatureProvider(@"CONNECTION_STRING_HERE");

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddFeatureFlags(options);
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseFeatureFlags(options);

            // IMPORTANT: Controlling access of the UI / API of this library is the responsibility of the user.
            // Apply authentication / authorization around the `UseFeatureFlagsUI` method as needed,
            // as this method wires up the various endpoints.
            app.UseFeatureFlagsUI(options);
        }
    }
}

Next, create feature flags like this in the ASP.NET Core assembly:

using RimDev.AspNetCore.FeatureFlags;

namespace MyApplication
{
    public class MyFeature : Feature
    {
        // Optional, displays on UI:
        public override string Description { get; } = "My feature description.";
    }
}

NoteFeatureFlagAssemblies to scan can also be configured in FeatureFlagOptions if you’d like to scan assemblies other than Assembly.GetEntryAssembly().

Now you can dependency inject any of your feature flags using the standard ASP.NET Core IoC!

public class MyController : Controller
{
    private readonly MyFeature myFeature;

    public MyController(MyFeature myFeature)
    {
        this.myFeature = myFeature;
    }

    // Use myFeature instance here, using myFeature.Value for the on/off toggle value.
}

UI

The UI wired up by UseFeatureFlagsUI is available by default at /_features. The UI and API endpoints can be modified in FeatureFlagOptions if you’d like, too.

In closing

We hope this helps you control your applications in production, enabling rapid development while controlling access to new functionality in a controlled manner – decoupled from your deployments. Enjoy!

ASP.NET Core Hosting :: How to Implement Custom Error Pages in ASP.NET MVC Core

$
0
0

We just recently saw people ask this questions on forums, so we decide to write short brief tutorial to make custom error pages in ASP.NET MVC Core.

So, let’s start how to implement custom error pages 404s and exceptions on this blog.

Custom error pages

Anyone know what is custom error pages? It is great looking view when something goes wrong in a production environment.

In development you would use:

app.UseDeveloperExceptionPage();

Now when an exception occurs, you will see a view that describes what went wrong and where.

But it should not be used in production as it could lead to security problems. Users might also consider your site less stable, and never visit again.

So we want to show them something that says something like:

Oops! Something went wrong. We are very sorry, please try again in a moment. If the error persists...

In case of a 404 status code, by default ASP.NET Core just returns a white page.

Instead we would like to show something like:

Hey that thing you tried to access does not exist. Please check the URL is correct.

Exception handler middleware

Let's start by handling exceptions properly.

In our application pipeline configuration, we will add the exception handler middleware:

if(!env.IsDevelopment())
{
    app.UseExceptionHandler("/error/500");
}

So what does this middleware do?

Well, put simply it:

  1. Calls the next middleware with a try-catch block
  2. If an exception is caught, the next middleware is called again with the request path set to what you gave as an argument

This re-execution means the original URL is preserved in the browser.

The controller and action that is implemented looks like this:

[Route("error")]
public class ErrorController : Controller
{
    private readonly TelemetryClient _telemetryClient;

    public ErrorController(TelemetryClient telemetryClient)
    {
        _telemetryClient = telemetryClient;
    }

    [Route("500")]
    public IActionResult AppError()
    {
        var exceptionHandlerPathFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
        _telemetryClient.TrackException(exceptionHandlerPathFeature.Error);
        _telemetryClient.TrackEvent("Error.ServerError", new Dictionary<string, string>
        {
            ["originalPath"] = exceptionHandlerPathFeature.Path,
            ["error"] = exceptionHandlerPathFeature.Error.Message
        });
        return View();
    }
}

I took a look at the source code of the exception handler middleware, and found that it sets this IExceptionHandlerPathFeature on the context before re-executing the request.

Here we access it to get the relative URL the user tried to access and the exception that occurred. We use Application Insights to track the exception.

The view is pretty simple:

@{
    ViewBag.Title = "Error occurred";
}

<h1>We have a problem</h1>

<p>Sorry, an error occurred while executing your request.</p>

Now when an exception is thrown:

  1. The exception is logged in Application Insights
  2. User gets a nice-looking view instead of a stack trace
  3. The original URL is preserved in the browser so the user can try to refresh
  4. The response comes back with a 500 status code so it is tracked as a failed request in Application Insights

Handling 404s

We also want to handle 404 status codes gracefully.

In this blog, it could happen because the URL did not map to a controller action. Or it might have, but we could not find something in the database.

404s are handled with a small middleware that is placed before the MVC middleware:

app.Use(async (ctx, next) =>
{
    await next();

    if(ctx.Response.StatusCode == 404 && !ctx.Response.HasStarted)
    {
        //Re-execute the request so the user gets the error page
        string originalPath = ctx.Request.Path.Value;
        ctx.Items["originalPath"] = originalPath;
        ctx.Request.Path = "/error/404";
        await next();
    }
});

Re-executing a request is not hard as you can see. We just call await next(); again.

Here we grab the original URL and put it in the HttpContext.Items collection.

This is the action that then handles the error in the ErrorController introduced earlier:

[Route("404")]
public IActionResult PageNotFound()
{
    string originalPath = "unknown";
    if (HttpContext.Items.ContainsKey("originalPath"))
    {
        originalPath = HttpContext.Items["originalPath"] as string;
    }
    _telemetryClient.TrackEvent("Error.PageNotFound", new Dictionary<string, string>
    {
        ["originalPath"] = originalPath
    });
    return View();
}

We track the event with a custom event in Application Insights, and include the original URL in the properties.

The view is quite simple again:

@{
    ViewBag.Title = "404";
}

<h1>404 - Page not found</h1>

<p>Oops, better check that URL.</p>

If you open the browser DevTools, you can again see we get the right status code: 404.

And the original URL is preserved in the browser.

Happy Coding!

ASP.NET Core Hosting - ASPHostPortal :: How to Integrate Stripe Payment with ASP.NET Core

$
0
0

Stripe is a service for doing online payments. It's easy to get started with it because they take care of both the frontend and the backend. The frontend scripting is available for many different frameworks like React, Android, IOS and of course JavaScript and with different levels of customization. The backend is also available in almost any backend framework one could wish for, like .NET. We will discuss the different options for a JavaScript frontend, the .NET package for Stripe as the title suggests, and lastly, the use of Webhooks.

Choosing a frontend option

The frontend uses tokens to represent the card’s information. It does so by preventing the default submission of the form and creating a token of the card’s information by contacting the Stripe servers. This ensures you never need to handle personal card information on your server. It is recommended to use a SSL certificate on the payment site to ensure no one can intercept the information that the client script sends.

Stripe.js is the most basic and lightweight option and the one most customizable. It supplies a clean multipart input where the user can fill in their card nr., expiration date and CVC nr. The input instantly detects the card type and validates of the card nr. and expiration date. You can read more about the integration of Stripe.js in Stripe's guide.

 

 

Secure payments

 

From the 4th of September 2019 new security standards will apply for online payments in the EU. So, if you are targeting an European or global customer segment, you should have this in mind. The EU council PSD2 continuously work on making online payment safer for the users. This requires payments to be done using an extra step of security. You have probably already seen such methods and the one most popularly used by different banks is 3D Secure. This is already an integrated part of the Checkout solution, but is not a supported feature in Stripe.js without performing some extra steps. To enable this for Stripe.js you will need to use a PaymentIntent.

Registering at Stripe.com

Before getting started with coding you need an account at Stripe. You get this by going to their register page and filling out the form. After you are done with this you can access the Stripe dashboard. A nice feature that we will need in this experimental test phase is the View test data, which you can enable/disable directly in the menu. This option switches between real and test payments, API keys and so on. To see and create API keys go to Developers>API keys. You have both publishable and secret keys, but you should never use the secret key on the frontend. These keys differ depending on if you are in testing mode or not, so make sure to switch to live keys when you publish your site.

 

 

The main menu in the Stripe dashboard

Creating a payment

We chose to use MVC in our example and have made a Controller for payments and associated views. We chose to use the Checkout for our frontend, because it has the simplest setup.

@{
    ViewData["Title"] = "Payment";
}

<div>
    <form action="/Payment/Processing" method="POST">
        <script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
                data-key="pk_test_YourPublishAbleKey"
                data-amount="@ViewBag.PaymentAmount"
                data-name="[My Company Name]"
                data-description="10 rubberducks for 1$ each"
                data-image=
https://stripe.com/img/documentation/checkout/marketplace.png
                data-locale="en"
                data-zip-code="true"
                data-label="Pay 10$">
        </script>
    </form>
</div>

The elements in the form are made by the referenced JavaScript, so this is all you need for the frontend for now. You can change the form to your liking by using the data attributes. An example could be to fill out the amount dynamically using a ViewModel or ViewBag as shown. Other options such as specifying the currency (US Dollars is the default) can be added as well and you can read more about this in Stripe's guide for Checkout. On submit, the form posts the inputs to the action specified, which include the strings stripeToken and stripeEmail by default. Stripe.js also creates the input named stripeToken on submit, so the frontend can easily be switched to that implementation.

To get started on the backend we first need to add the package NuGet Stripe.net to our project. We then need to define the API key that we will use and a good convention is to set this in the Configure-method in Startup.cs:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    //Your other configuration
    StripeConfiguration.SetApiKey(Configuration["Stripe:TestSecretKey"]);
}

We refence our API key using User Secrets, but you could use App Settings or an inline string instead, if that fits your style better.

We can now make the controller for our Payment Views and the post:

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using Stripe;

namespace StripeTest.Controllers
{
    public class PaymentController : Controller
    {
        private int amount = 100;
        public IActionResult Index()
        {
            ViewBag.PaymentAmount = amount;
            return View();
        }

        [HttpPost]
        public IActionResult Processing(string stripeToken, string stripeEmail)
        {
            Dictionary<string, string> Metadata = new Dictionary<string, string>();
            Metadata.Add("Product", "RubberDuck");
            Metadata.Add("Quantity", "10");
            var options = new ChargeCreateOptions
            {
                Amount = amount,
                Currency = "USD",
                Description = "Buying 10 rubber ducks",
                SourceId = stripeToken,
                ReceiptEmail = stripeEmail,
                Metadata = Metadata
            };
            var service = new ChargeService();
            Charge charge = service.Create(options);
            return View();
        }
    }
}

We take the two parameters stripeToken and stripeEmail in our action, but could add more, like information about the billing address, if you enable that in the frontend (if you have more inputs than this, a better approach would be to use a model for the form, but for now this should be fine).

We would like to add some metadata to the charge which we will use later. This is done using a Dictionary.

We then create a ChargeCreateOption object which contains the information about the Charge, where we pass in stripeToken and the Metadata Dictionary. We then create a ChargeService and use the ChargeCreateOption to make the charge. The Status of the Charge is at first pending and will change to either succeeded or failed when the charge has been processed by Stripe.

Respond to the payment

But what now? How do we know the Status of the charge? There are two different ways of getting the Status of the charge.

We can Retrieve the charge. This is done using a ChargeService again and using the action .Get(id) which takes the id of the Charge as a parameter, which we would have to save when we create it. The status could still be pending when we make the request, so we would have to run the request multiple times in intervals to check.

We can use Webhooks. In the Dashboard, we can specify an endpoint that will be called when a Charge changes status and use this to take actions on our server when we need to and not make unnecessary requests.

We decide to use Webhooks. We first need to make the Webhook on our page. We simply add another action to our Controller:

private readonly string WebhookSecret = "whsec_OurSigningSecret";

//Previous actions

[HttpPost]
public IActionResult ChargeChange()
{
    var json = new StreamReader(HttpContext.Request.Body).ReadToEnd();

    try
    {
        var stripeEvent = EventUtility.ConstructEvent(json,
            Request.Headers["Stripe-Signature"], WebhookSecret, throwOnApiVersionMismatch: true);
        Charge charge = (Charge)stripeEvent.Data.Object;
        switch (charge.Status)
        {
            case "succeeded":
                //This is an example of what to do after a charge is successful
                charge.Metadata.TryGetValue("Product", out string Product);
                charge.Metadata.TryGetValue("Quantity", out string Quantity);
                Database.ReduceStock(Product, Quantity);
                break;
            case "failed":
                //Code to execute on a failed charge
                break;
        }
    }
    catch (Exception e)
    {
        e.Ship(HttpContext);
        return BadRequest();
    }
    return Ok();
}

We have made the Action ChargeChange which starts by reading the body that was passed with the post. We then try to construct the event and cast it to the Charge type.

Now we just need to have Stripe call our Webhook, which is done in the dashboard in the menu Developers>Webhooks and selecting Add endpoint. We then enter the path of our webhook, which would be something like:

https://mysite.com/Payment/ChargeChange/

We can also choose to have it only access our webhook for certain types of changes, like only when a it changes to charge.succeeded or charge.failed. After this you can go into the Endpoint in the list and see our Webhook Secret.

 

This is a basic start for how to work with Stripe. They have many more features we didn't get to cover, including the new PaymentIntent and the setup of Subscriptions. It's easy to imagine many more technologies that Stripe could be used together with, like SignalR for real-time response on a status update of a Charge. 

ASP.NET 4.6 Hosting :: How to Solve Error "Could not create SSL/TLS secure channel"

$
0
0

Yeap, ASP.NET Core 2.2 has been released and ASP.NET Core will release soon. But, there are many other users that still using previous ASP.NET version like ASP.NET 4.6. I just found in forum that people encounter error setting up SSL/TLS in .NET 4.6. The following is the error message

System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel

With SSL3 and TLS1.0 being deprecated, I figured this had to do with a version mismatch between the browser and the server. In fact, that was true. The reason why the security protocol didn’t default to TLS 1.2 in my application is because it was running on .NET 4.6.2, and in .NET 4.6x there is no default set for the security protocol. Also, it was running on a version of Windows (2012 R2) that didn’t have newer versions of TLS enabled by default.

One solution to this is to recompile your website either specifying a default or targeting .NET 4.7, which does have a default value of SecurityProtocolType.SystemDefault. According to the Microsoft .NET documentation, this setting “allows .NET Framework networking APIs based on SslStream (such as FTP, HTTP, and SMTP) to inherit the default security protocols from the operating system or from any custom configurations performed by a system administrator”. In my case, that may not have helped since the OS didn’t have TLS1.2 enabled.

Strong Cryptography Mode

I wasn’t able to recompile the application at the time, anyway, and so needed to find another way to fix the issue by reconfiguring the OS. In the end, I was able to fix the issue by enabling something called “strong cryptography mode” in Windows on the web server, which you can read more background about here.

To make the change, I simply had to run the two commands below in an elevated PowerShell prompt on the server. The first command is for x64 .NET and the second for x86 .NET.

Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord

After those commands are run, you can run the following command to verify the setup:

[Net.ServicePointManager]::SecurityProtocol

This will list the enabled SSL/TLS protocols, which in my case now includes TLS12 (that is, TLS 1.2).

Finally, I simply reset IIS to restart my application, and I now no longer get the “Could not create SSL/TLS secure channel” exception and the API longer returns HTTP 500 responses!

Hope this helps!

ASP.NET Core Hosting :: Error Logging in ASP.NET Core Application

$
0
0

I find it tough to believe that many developers do not use any Logging library in their applications. For a Web Applications, Error Logging is one of the key attributes to help troubleshoot application bugs. In many cases, developers don’t have direct access to his application after deployment. So, in order to assure the application’s quality, we must be aware of bugs in our application even after deployment.

There are many open-source libraries available for Error Logging. For .Net, most trusted & commonly used frameworks are NLog & Log4Net. Both frameworks make it simpler to send our application logs in different places like databases, files, log management systems & many other places. We can also Email our Critical logs. The awesome thing is that we can send the logs to a different place just by changing the config file.

By using Error Logging in an Application, we can categorize our logs at different levels. Here’s the list.

LEVELS

  • Info – Info Message, enabled in production mode
  • Warning – Warning Messages, temporary & recoverable problems.
  • Error – Error Messages, programming exceptions.
  • Trace – Very detailed Logs, usually enabled during the development phase.
  • Debug – Debugging information, less information than Traces.
  • Fatal – Serious Errors, failures that need immediate attention.

As I have discussed above, Error Logging Frameworks also facilitates us to send our application’s log to different destinations, we called them targets.

TARGETS

  • Files- We can log our messages into a file.
  • Databases – Important Logs can also be stored in a database. Usually, we store only those logs to a database which we need to display in our application.
  • Console – In Console Applications, best available target to display logs is console itself.
  • Email – In case of fatal errors which need attention we need to aware the team with the failure. so it’s always a good idea to email those logs.

Let’s have a quick look at available Logging frameworks for .Net Core. After deciding the better one, we’ll implement the winner logging framework in our Application. 

CHOOSING A FRAMEWORK

Here’s the result of a speed comparison of 5 most popular error logging framework for .Net & .Net Core

So clearly, NLog is the winner here because it’s taking the minimum time to Log.

Without wasting our time let’s see how we can install, configure and use NLog in our Application.

CREATING A PROJECT

I’m going to use VS Code to create an empty web project.

Create an empty Web Application using this command

dotnet new web

after this add the Code below to your “Startup.cs” File to ready your Application.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    }
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

Now create a new Folder as “Controllers” at the root level of your Project & inside this folder create a controller class as “HomeController.cs”

INSTALLING NLOG

After creating the project, we need to add NLog Library.

NLog is available at Nuget. You can install it in the way you like it. I’m going to use the .Net CLI. So, here’s the command to install NLog

dotnet add package NLog

CONFIGURATION

Now Add a configuration file at the root of your project with the name as “NLog.config” & paste this Code

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns=http://www.nlog-project.org/schemas/NLog.xsd
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <targets>
        <target name="logfile" xsi:type="File" fileName="Logs.txt" />
        <target name="logconsole" xsi:type="Console" />
    </targets>
    <rules>
        <logger name="*" minlevel="Info" writeTo="logconsole" />
        <logger name="*" minlevel="Debug" writeTo="logfile" />
    </rules>
</nlog>

There’s another way to configure NLog but I’ll recommend using XML configuration. In this case, you’ll be able to edit you Logging configuration even after publishing your application.

If you still don’t like configuring NLog using above way then you can do the same by programmatically.

Here’s the alternate way.

var config = new NLog.Config.LoggingConfiguration();
var logfile = new NLog.Targets.FileTarget("logfile") { FileName = "Logs.txt" };
var logconsole = new NLog.Targets.ConsoleTarget("logconsole");           

config.AddRule(LogLevel.Info, LogLevel.Fatal, logconsole);
config.AddRule(LogLevel.Debug, LogLevel.Fatal, logfile);           

NLog.LogManager.Configuration = config;

you can add this code to your “Program.cs” or “Startup.cs”.

WRITING LOGS

Now Add the code below in your “HomeController.cs” inside your Controllers Folder.

using Microsoft.AspNetCore.Mvc;
using NLog;
public class HomeController : Controller
{
    private static Logger logger = LogManager.GetCurrentClassLogger();
    public void Index()
    {
        logger.Debug("Hello from Home Controller...");
    }
}

Run your application & go to the Home Controller URL. e.g. http://localhost:*/Home

Now you’ll find your “Logs.txt” here => bin -> Debug -> netcoreapp

Here’s what I got in my “Logs.txt” File

2019-02-21 13:17:49.4574|DEBUG|NLogTutorials.HomeController|Hello from Home Controller...

 

Viewing all 427 articles
Browse latest View live