All About ASP.NET and ASP.NET Core 2 Hosting BLOG

Tutorial and Articles about ASP.NET and the latest ASP.NET Core

ASP.NET Hosting :: How to Setup URL Redirection

clock November 15, 2018 07:07 by author Jervis

We have so many clients asking about this issue. So, we decide to write this tutorial and hope this information can help other people too. In this review, we will write simple tutorial about how to setup http/https redirection in IIS.

There are lots of routing options accessible in ASP.NET but still it comes a time when you need to manipulate a URL and manipulating it outside a code comes handy. When this happens, the best you can do id to use IIS Rewrite Module. Transforming various URL’s out of code enables you to do various things including performing redirections for archive or transferred content without interfering with the code, you can easily implement SEO optimizations and tweaks quickly and easily without code and many more. Below is a collection of useful IIS rewrite rules that will help you understand IIS rewrites.

Useful IIS Rewrite Rules

Adding www Prefix

This is a basic rule that adds prefix “www” to any URL you need. This is a requirement for SEO.

Redirection from Domain 1 to Domain 2

This rule comes handy when you change the name of your site or may be when you need to catch and alias and direct it to your main site. If the new and the old URLs share some elements, then you could just use this rule to have the matching pattern together with the redirect target being.

HTTPS/HTTP Redirection

Redirecting users from HTTP to HTTPS is one of the reasons that you need to apply useful IIS rewrite rules. It can lead to conditional statements while looking for dev/test mode in your code. This rules allows you to handle the redirection without much statements which is tidier.

There is a pair of rules in this case each for one of the two ways. In both the rules, a check is performed to verify that the protocol used is http/https. The rules work on the same URL patterns or the similar lists of pages to match. For the redirect to HTTP, it is not about matching the pages; it is a reverse of the first rule and usually have a number of .NET/site paths that are excluded.

Setup Redirection Using IIS

Above steps is to setup URL redirection via your code. But, if you manage your own server, you can also setup redirection via IIS. The following is the steps

1. Download and install the “URL Rewrite” module.

2. Open the “IIS Manager” console and select the website you would like to apply the redirection to in the left-side menu:



3. Double-click on the “URL Rewrite” icon.

4. Click “Add Rule(s)” in the right-side menu.

5. Select “Blank Rule” in the “Inbound” section, then press “OK”:

6. Enter any rule name you wish.

7. In the “Match URL” section:

- Select “Matches the Pattern” in the “Requested URL” drop-down menu 
- Select “Regular Expressions” in the “Using” drop-down menu 
- Enter the following pattern in the “Match URL” section: “(.*)” 
- Check the “Ignore case” box

 

 

8. In the “Conditions” section, select “Match all” under the “Logical Grouping” drop-down menu and press “Add”.

9. In the prompted window:

- Enter “{HTTPS}” as a condition input 
- Select “Matches the Pattern” from the drop-down menu 
- Enter “^OFF$” as a pattern 
- Press “OK”

10. In the “Action” section, select “Redirect” as the action type and specify the following for “Redirect URL”:

https://{HTTP_HOST}/{R:1}

11. Check the “Append query string” box.

12.Select the Redirection Type of your choice. The whole “Action” section should look like this:

 

NOTE: There are 4 redirect types of the redirect rule that can be selected in that menu: 

- Permanent (301) – preferable type in this case, which tells clients that the content of the site is permanently moved to the HTTPS version. Good for SEO, as it brings all the traffic to your HTTPS website making a positive effect on its ranking in search engines. 
- Found (302) – should be used only if you moved the content of certain pages to a new place *temporarily*. This way the SEO traffic goes in favour of the previous content’s location. This option is generally not recommended for a HTTP/HTTPS redirect. 
- See Other (303) – specific redirect type for GET requests. Not recommended for HTTP/HTTPS. 
- Temporary (307) – HTTP/1.1 successor of 302 redirect type. Not recommended for HTTP/HTTPS.

13. Click on “Apply” on the right side of the “Actions” menu.

The redirect can be checked by accessing your site via http:// specified in the URL. To make sure that your browser displays not the cached version of your site, you can use anonymous mode of the browser.

The rule is created in IIS, but the site is still not redirected to https://

Normally, the redirection rule gets written into the web.config file located in the document root directory of your website. If the redirection does not work for some reason, make sure that web.config exists and check if it contains the appropriate rule.

To do this, follow these steps:

1. In the sites list of IIS, right-click on your site. Choose the “Explore” option:

 

2. “Explore” will open the document root directory of the site. Check if the web.config file is there.

3. The web.config file must have the following code block:

<configuration> 
<system.webServer> 
<rewrite> 
<rules> 
<rule name="HTTPS force" enabled="true" stopProcessing="true"> 
<match url="(.*)" /> 
<conditions> 
<add input="{HTTPS}" pattern="^OFF$" /> 
</conditions> 
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" /> 
</rule> 
</rules> 
</rewrite> 
</system.webServer> 
</configuration>

4. If the web.config file is missing, you can create a new .txt file, put the aforementioned code there, save and then rename the file to web.config.

 

 



ASP.NET Core Hosting :: How to Fix Error "An error occurred while starting the application" in ASP.NET Core

clock November 9, 2018 09:43 by author Jervis

Previously, we have written tutorial about how to fix 502.5 error that you face when publishing your ASP.NET Core application. Another issue that you might face when publishing your .net Core application is:

“An error occurred while starting the application.  .NET Framework <version number> | Microsoft.AspNetCore.Hosting version <version number> | Microsoft Windows <version number>”

It looks like:

What happened?

It basically means something really bad happened with your app.  Some things that might have gone wrong:

  • You might not have the correct .NET Core version installed on the server.
  • You might be missing DLL’s
  • Something went wrong in your Program.cs or Startup.cs before any exception handling kicked in

Event Viewer (Probably) Won’t Show You Anything

If you’re running on Windows and behind IIS, you might immediately go to the Event Viewer to see what happened based on your previous ASP.NET knowledge.  You’ll notice that the error is not there.  This is because Event Logging must be wired up explicitly and you’ll need to use the Microsoft.Extensions.Logging.EventLog package, and depending on the error, you might not have a chance to even catch it to log to the Event Viewer.

How to figure out what happened (if running on IIS)

Instead of the Event Viewer, if you’re running behind IIS, we can log the request out to a file.  To do that:

  1. Open your web.config
  2. Change stdoutLogEnabled=true
  3. Create a logs folder
    - Unfortunately, the AspNetCoreModule doesn’t create the folder for you by default. If you forget to create the logs folder, an error will be logged to the Event Viewer that says: Warning: Could not create stdoutLogFile \\?\YourPath\logs\stdout_timestamp.log, ErrorCode = -2147024893.
    -
    The “stdout” part of  the value “.\logs\stdout” actually references the filename not the folder.  Which is a bit confusing.
  4. Run your request again, then open the \logs\stdout_*.log file

Note – you will want to turn this off after you’re done troubleshooting, as it is a performance hit.

So your web.config’s aspNetCore element should look something like this

 <aspNetCore processPath=”.\YourProjectName.exe” stdoutLogEnabled=”true” stdoutLogFile=”.\logs\stdout” />

Doing this will log all the requests out to this file and when the exception occurs, it will give you the full stack trace of what happened in the \logs\stdout_*.log file

 

Hope this helps. In case, you need ASP.NET Core hosting, you can always try our services start from $1.00/month.



ASP.NET Core 2 Hosting :: How to Fix Error 502.5 When Deploy Your ASP.NET Core

clock November 7, 2018 08:25 by author Jervis

I decide to make this tutorial as most of our users also experience same problem when deploying their ASP.NET Core application.

I recently hit this problem after manually modifying the web.config file. Fortunately, the problem is easy to fix.

In this post, we see two different causes of this error, two different solutions for the first cause, a solution for the second cause, and learn what needs to be in web.config for ASP.NET Core to operate.

The Error

Here is a screenshot of the HTTP Error 502.5 - Process Failure error. You'll see this, in your browser, when making a request to your ASP.NET Core application, after deployment, if you have this issue.

Why do I get the error?

 

The HTTP Error 502.5 - Bad Gateway and HTTP Error 502.5 - Process Failure error messages occur in ASP.NET Core when IIS fails to execute the dotnet process.

I've seen this error happen for two different reasons:

  • .NET Core Runtime is not installed
  • web.config file has not been transformed

How to Fix This Error?

This is very simple and easy to fix this issue. What you need to make sure is that your hosting provider support or already installed the latest ASP.NET Core on their hosting environment.

1. Install Latest .NET Core Runtime

You can download the latest .NET Core runtime from Microsoft's .NET download page.

For Windows, you'll usually want the latest .NET Core runtime (currently v2.1.1), as highlighted in the following screenshot:

This will get you the Windows Hosting Bundle Installer, which will install both the x86 and x64 runtimes on Windows Server.

2. Publish a Self-Contained Deployment

If you don't want to install the .NET Core Runtime. An alternative for .NET Core web applications is to publish them in the Self-Containeddeployment mode, which includes the required .NET Runtime files alongside your application.

You can select this option from the advanced publish settings screen in Visual Studio: 

If you go with this option, you'll also need to choose a target runtime: win-x86, win-x64, osx-x64, or linux-x64. Because self-contained deployments are not portable.

3. Transform your web.config file

Another reason for this error to occur is when you deploy an untransformed web.config file. This is likely to be your issue if you had a previously working web application and merely deployed a new version of it.

ASP.NET Core Web Config

In ASP.NET Core applications, the web.config file contains a handler that directs requests to the AspNetCoreModule and an aspNetCoreelement that defines and configures the ASP.NET Core process to execute your web application.

Here is a minimal web.config file for an ASP.NET Core application:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 
<system.webServer>
   
<handlers>
     
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
   
</handlers>
   
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="true"
       
stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
 
</system.webServer>
</configuration>

Note that it's possible that you don't have a web.config file in your ASP.NET Core project. If you do not, one will be generated for you when publishing the project, as IIS and IIS Express require a web.config file when hosting an ASP.NET Core web app.

The Issue

The untransformed web.config contains the variables %LAUNCHER_PATH% and %LAUNCHER_ARGS% rather than the correct paths. When IIS tries to run ASP.NET Core, it uses %LAUNCHER_PATH% and %LAUNCHER_ARGS% rather than the correct path and arguments.

To fix the HTTP Error 502.5 in ASP.NET Core, you need to transform the web.config and replace the untransformed web.config file on the IIS web server.

How do I transform web.config?

This transformation takes place when you choose to publish your web application. The transformed web.config ends up in the published output folder. Therefore, you simply need to publish your web application and copy the resulting web.config file onto the server.

In a transformed web.config file, the aspNetCore element will look something like this:

<aspNetCore processPath="dotnet" arguments=".\MyApplication.dll" stdoutLogEnabled="true"
    stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" />

%LAUNCHER_PATH% has been replaced by dotnet and %LAUNCHER_ARGS% has been replaced by the path to the main web application dll .\MyApplication.dll.



ASP.NET Core 2 Hosting :: How to Create Simple Shoutbox Using ASP.NET Core Razor Pages

clock November 6, 2018 10:44 by author Jervis

ASP.NET Core 2 comes with Razor Pages that allow developers to build simple web applications with less overhead compared to MVC. The emphasis is on the word “simple” as Razor Pages doesn’t come with patterns suitable for bigger and more complex applications. For this, we have MVC that is flexible enough to build applications that will grow over years. This blog post uses a simple shoutbox application to illustrate how to build applications using Razor Pages.

Shoutbox Application

This post introduces how to build a simple and primitive shoutbox application using ASP.NET Core and Razor Pages. We will also use SQL Server LocalDb and Entity Framework Core code-first to make things more interesting. The goal of this post is to demonstrate how to use Razor Pages pages with and with-out a backing model.

We will build a fully functional application you can use to further dig around and discover the secrets of Razor Pages.

Creating a Razor Pages Application

Let’s start with a new ASP.NET Core Razor Pages project. Yes, now there is a new template for this. 

 

Razor Pages projects have a similar structure to MVC ones, but, as there are some differences, like Pages folder, and as Razor Pages doesn’t have controllers, we don’t have a controllers folder. Also, there’s no folder for views.

Database, Data Context, and Shoutbox Entity

We will use SQL Server LocalDB as our database and we will go with Entity Framework Core code-first. The first thing to do is to modify appsettings.json and add a connection string: I leave everything else like it is.

{
  "ConnectionStrings": {
    "ShoutBoxContext": "Server=(localdb)\\mssqllocaldb;Database=ShoutBoxContext;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  }

Let’s also create a simple entity class for our shoutbox item. As we don’t create model mappings we have to use data annotations to let the data context know how to create a database table.

public class ShoutBoxItem
{
    [Key]
    public int Id { get; set; }
    [Required]
    public DateTime? Time { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    public string Message { get; set; }
}

To communicate with the database we need a database context class too. We keep our database context as minimal as reasonably possible.

public class ShoutBoxContext : DbContext
{
    public ShoutBoxContext(DbContextOptions<ShoutBoxContext> options) : base(options)
    { }
    public DbSet<ShoutBoxItem> ShoutBoxItems { get; set; }
}

Finally, we need to introduce our database context to a framework-level dependency injection mechanism. We can do this with the ConfigureServices()method of the Startup class.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddDbContext<ShoutBoxContext>(options => {n
        options.UseSqlServer(Configuration.GetConnectionString("ShoutBoxContext"));
    });
    services.AddTransient<ShoutBoxContext>();
}

Before using the database, we must ensure it is there and available. For this, we add an EnsureCreated()call to the ends of the Configure() method of the Startup class.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }
    app.UseStaticFiles();
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
    app.ApplicationServices.GetRequiredService<ShoutBoxContext>()
                           .Database
                           .EnsureCreated();
}

Now we have everything we need to start building the user interface for our simple shoutbox application.

Building Shout List

Our simple application will show the 100 latest shouts as a list on the front page. This view is an example of a page with no code-behind file. All the work is done on the page itself. We will use it to get our data context to the page.

@page
@inject RazorPagesShoutBox.Data.ShoutBoxContext dataContext
@{
    ViewData["Title"] = "Home Page";
    var shouts = dataContext.ShoutBoxItems
                            .OrderByDescending(s => s.Time)
                            .Take(100)
                            .ToList();
}
<h2>@ViewData["Title"]</h2>
<div class="row">
    <div class="col-md-10">
        @if (shouts.Any())
        {
            foreach (var shout in shouts)
            {
                <p>
                    <strong>@shout.Name</strong> | @shout.Time.ToString()<br />
                    @Html.Raw(shout.Message.Replace("\r\n", "<br />"))
                </p>
            }
        }
        else
        {
            <p>No shouts... be the firts one!</p>
        }
    </div>
</div>
<a href="AddShout">Add shout</a>

At the end of the page, we have a link to the page where the user can add a new shout.

Building New Shout Form

To let users shout, we create a separate page and this time we will use code-behind file where the model for the page is defined. Notice the @model directive in the page code.

@page
@model AddShoutModel
@{
    ViewData["Title"] = "Add shout";
}
<h2>@ViewData["Title"]</h2>
<div class="row">
    <div class="col-md-10">
        <form method="post">
            <div class="form-group">
                <label asp-for="Item.Name"></label>
                <input class="form-control" asp-for="Item.Name" />
                @Html.ValidationMessageFor(m => m.Item.Name)
            </div>
            <div class="form-group">
                <label asp-for="Item.Message"></label>
                <textarea class="form-control" asp-for="Item.Message"></textarea>
                @Html.ValidationMessageFor(m => m.Item.Message)
            </div>
            <input type="hidden" asp-for="Item.Time" />
            <button type="submit" class="btn-default">Shout it!</button>
        </form>
    </div>
</div>

All models that support pages are inherited from the PageModel class. We use constructor injection to get our data context to the page model. The model we want to show on the page is represented by Item property. The BindProperty attribute tells ASP.NET Core that data from the form must be bound to this property. Without it, we must write code to extract values from the request and do all the dirty work by ourselves. The OnGet() method of the page model is called when the page is loaded using the HTTP GET method and OnPost() is called when a POST was made.

public class AddShoutModel : PageModel
{
    private readonly ShoutBoxContext _context;
    public AddShoutModel(ShoutBoxContext context)
    {
        _context = context;
    }
    [BindProperty]
    public ShoutBoxItem Item { get; set; }
    public void OnGet()
    {
        if (Item == null)
        {
            Item = new ShoutBoxItem();
        }
        Item.Time = DateTime.Now;
    }
    public IActionResult OnPost()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
        Item.Id = 0;
        _context.ShoutBoxItems.Add(Item);
        _context.SaveChanges();
        return RedirectToPage("Index");
    }
}

It’s time to run the application and make some serious shouts!

Wrapping Up

Razor Pages provides us with a thinner model to build applications and it’s suitable for small applications. As it is part of ASP.NET Core MVC, it supports many features that come with MVC. The PageModel is like a mix of models and controllers in MVC and its purpose is to provide the separation of presentation and logic. We can use Razor Pages to build pages with or without a backing model and it is completely up to us to decide which way to go. 



ASP.NET Core Hosting - Understanding File uploads in ASP.NET Core

clock October 23, 2018 08:57 by author Kenny

Uploading file or image in ASP.NET Core is very easy. ASP.NET MVC actions support uploading of one or more files using simple model binding for smaller files or streaming for larger files. In this article we will learn how to upload any file in ASP.NET Core. We will see how can we use different features of ASP.NET Core to upload small file as well as any large file.

Uploading small files with model binding

To upload small files, you can use a multi-part HTML form or construct a POST request using JavaScript. An example form using Razor, which supports multiple uploaded files, is shown below:

<form method="post" enctype="multipart/form-data" asp-controller="UploadFiles" asp-action="Index">
    <div class="form-group">
        <div class="col-md-10">
            <p>Upload one or more files using this form:</p>
            <input type="file" name="files" multiple="">
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-10">
            <input type="submit" value="Upload">
        </div>
    </div>
</form>

In order to support file uploads, HTML forms must specify an enctype of multipart/form-data. The files input element shown above supports uploading multiple files. Omit the multiple attribute on this input element to allow just a single file to be uploaded. The above markup renders in a browser as:

Uploading small files with model binding

The individual files uploaded to the server can be accessed through Model Binding using the IFormFile interface. IFormFile has the following structure:

public interface IFormFile
{
    string ContentType { get; }
    string ContentDisposition { get; }
    IHeaderDictionary Headers { get; }
    long Length { get; }
    string Name { get; }
    string FileName { get; }
    Stream OpenReadStream();
    void CopyTo(Stream target);
    Task CopyToAsync(Stream target, CancellationToken cancellationToken = null);
}

Warning:- Don't rely on or trust the FileName property without validation. The FileName property should only be used for display purposes.

When uploading files using model binding and the IFormFile interface, the action method can accept either a single IFormFile or an IEnumerable<IFormFile> (or List<IFormFile>) representing several files. The following example loops through one or more uploaded files, saves them to the local file system, and returns the total number and size of files uploaded.

Warning:- The following code uses GetTempFileName, which throws an IOException if more than 65535 files are created without deleting previous temporary files. A real app should either delete temporary files or use GetTempPath and GetRandomFileName to create temporary file names. The 65535 files limit is per server, so another app on the server can use up all 65535 files.

[HttpPost("UploadFiles")]
public async Task<IActionResult> Post(List<IFormFile> files)
{
    long size = files.Sum(f => f.Length);
 
    // full path to file in temp location
    var filePath = Path.GetTempFileName();
 
    foreach (var formFile in files)
    {
        if (formFile.Length > 0)
        {
            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await formFile.CopyToAsync(stream);
            }
        }
    }
 
    // process uploaded files
    // Don't rely on or trust the FileName property without validation.
 
    return Ok(new { count = files.Count, size, filePath});
}

Files uploaded using the IFormFile technique are buffered in memory or on disk on the web server before being processed. Inside the action method, the IFormFile contents are accessible as a stream. In addition to the local file system, files can be streamed to Azure Blob storage or Entity Framework.

To store binary file data in a database using Entity Framework, define a property of type byte[] on the entity:

public class ApplicationUser : IdentityUser
{
    public byte[] AvatarImage { get; set; }
}
Specify a viewmodel property of type IFormFile:
public class RegisterViewModel
{
    // other properties omitted
 
    public IFormFile AvatarImage { get; set; }
}

Note:- IFormFile can be used directly as an action method parameter or as a viewmodel property, as shown above.

Copy the IFormFile to a stream and save it to the byte array:

// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
    ViewData["ReturnUrl"] = returnUrl;
    if  (ModelState.IsValid)
    {
        var user = new ApplicationUser {
          UserName = model.Email,
          Email = model.Email
        };
        using (var memoryStream = new MemoryStream())
        {
            await model.AvatarImage.CopyToAsync(memoryStream);
            user.AvatarImage = memoryStream.ToArray();
        }
    // additional logic omitted
 
    // Don't rely on or trust the model.AvatarImage.FileName property
    // without validation.
}

Note:- Use caution when storing binary data in relational databases, as it can adversely impact performance.

Uploading large files with streaming

If the size or frequency of file uploads is causing resource problems for the app, consider streaming the file upload rather than buffering it in its entirety, as the model binding approach shown above does. While using IFormFile and model binding is a much simpler solution, streaming requires a number of steps to implement properly.

Note:- Any single buffered file exceeding 64KB will be moved from RAM to a temp file on disk on the server. The resources (disk, RAM) used by file uploads depend on the number and size of concurrent file uploads. Streaming is not so much about perf, it's about scale. If you try to buffer too many uploads, your site will crash when it runs out of memory or disk space.

The following example demonstrates using JavaScript/Angular to stream to a controller action. The file's antiforgery token is generated using a custom filter attribute and passed in HTTP headers instead of in the request body. Because the action method processes the uploaded data directly, model binding is disabled by another filter. Within the action, the form's contents are read using a MultipartReader, which reads each individual MultipartSection, processing the file or storing the contents as appropriate. Once all sections have been read, the action performs its own model binding.

The initial action loads the form and saves an antiforgery token in a cookie (via the GenerateAntiforgeryTokenCookieForAjax attribute):

[HttpGet]
[GenerateAntiforgeryTokenCookieForAjax]
public IActionResult Index()
{
    return View();
}

The attribute uses ASP.NET Core's built-in Antiforgery support to set a cookie with a request token:

public class GenerateAntiforgeryTokenCookieForAjaxAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext context)
    {
        var antiforgery = context.HttpContext.RequestServices.GetService<IAntiforgery>();
 
        // We can send the request token as a JavaScript-readable cookie,
        // and Angular will use it by default.
        var tokens = antiforgery.GetAndStoreTokens(context.HttpContext);
        context.HttpContext.Response.Cookies.Append(
            "XSRF-TOKEN",
            tokens.RequestToken,
            new CookieOptions() { HttpOnly = false });
    }
}

Angular automatically passes an antiforgery token in a request header named X-XSRF-TOKEN. The ASP.NET Core MVC app is configured to refer to this header in its configuration in Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    // Angular's default header name for sending the XSRF token.
    services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
 
    services.AddMvc();
}

The DisableFormValueModelBinding attribute, shown below, is used to disable model binding for the Upload action method.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        var formValueProviderFactory = context.ValueProviderFactories
            .OfType<FormValueProviderFactory>()
            .FirstOrDefault();
        if (formValueProviderFactory != null)
        {
            context.ValueProviderFactories.Remove(formValueProviderFactory);
        }
 
        var jqueryFormValueProviderFactory = context.ValueProviderFactories
            .OfType<JQueryFormValueProviderFactory>()
            .FirstOrDefault();
        if (jqueryFormValueProviderFactory != null)
        {
            context.ValueProviderFactories.Remove(jqueryFormValueProviderFactory);
        }
    }
 
    public void OnResourceExecuted(ResourceExecutedContext context)
    {
    }
}

Since model binding is disabled, the Upload action method doesn't accept parameters. It works directly with the Request property of ControllerBase. A MultipartReader is used to read each section. The file is saved with a GUID filename and the key/value data is stored in a KeyValueAccumulator. Once all sections have been read, the contents of the KeyValueAccumulator are used to bind the form data to a model type.

The complete Upload method is shown below:

Warning:- The following code uses GetTempFileName, which throws an IOException if more than 65535 files are created without deleting previous temporary files. A real app should either delete temporary files or use GetTempPath and GetRandomFileName to create temporary file names. The 65535 files limit is per server, so another app on the server can use up all 65535 files.

// 1. Disable the form value model binding here to take control of handling
//    potentially large files.
// 2. Typically antiforgery tokens are sent in request body, but since we
//    do not want to read the request body early, the tokens are made to be
//    sent via headers. The antiforgery token filter first looks for tokens
//    in the request header and then falls back to reading the body.
[HttpPost]
[DisableFormValueModelBinding]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Upload()
{
    if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
    {
        return BadRequest($"Expected a multipart request, but got {Request.ContentType}");
    }
 
    // Used to accumulate all the form url encoded key value pairs in the
    // request.
    var formAccumulator = new KeyValueAccumulator();
    string targetFilePath = null;
 
    var boundary = MultipartRequestHelper.GetBoundary(
        MediaTypeHeaderValue.Parse(Request.ContentType),
        _defaultFormOptions.MultipartBoundaryLengthLimit);
    var reader = new MultipartReader(boundary, HttpContext.Request.Body);
 
    var section = await reader.ReadNextSectionAsync();
    while (section != null)
    {
        ContentDispositionHeaderValue contentDisposition;
        var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition);
 
        if (hasContentDispositionHeader)
        {
            if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
            {
                targetFilePath = Path.GetTempFileName();
                using (var targetStream = System.IO.File.Create(targetFilePath))
                {
                    await section.Body.CopyToAsync(targetStream);
 
                    _logger.LogInformation($"Copied the uploaded file '{targetFilePath}'");
                }
            }
            else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition))
            {
                // Content-Disposition: form-data; name="key"
                //
                // value
 
                // Do not limit the key name length here because the
                // multipart headers length limit is already in effect.
                var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name);
                var encoding = GetEncoding(section);
                using (var streamReader = new StreamReader(
                    section.Body,
                    encoding,
                    detectEncodingFromByteOrderMarks: true,
                    bufferSize: 1024,
                    leaveOpen: true))
                {
                    // The value length limit is enforced by MultipartBodyLengthLimit
                    var value = await streamReader.ReadToEndAsync();
                    if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase))
                    {
                        value = String.Empty;
                    }
                    formAccumulator.Append(key, value);
 
                    if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit)
                    {
                        throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded.");
                    }
                }
            }
        }
 
        // Drains any remaining section body that has not been consumed and
        // reads the headers for the next section.
        section = await reader.ReadNextSectionAsync();
    }
 
    // Bind form data to a model
    var user = new User();
    var formValueProvider = new FormValueProvider(
        BindingSource.Form,
        new FormCollection(formAccumulator.GetResults()),
        CultureInfo.CurrentCulture);
 
    var bindingSuccessful = await TryUpdateModelAsync(user, prefix: "",
        valueProvider: formValueProvider);
    if (!bindingSuccessful)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
    }
 
    var uploadedData = new UploadedData()
    {
        Name = user.Name,
        Age = user.Age,
        Zipcode = user.Zipcode,
        FilePath = targetFilePath
    };
    return Json(uploadedData);
}

Troubleshooting

Below are some common problems encountered when working with uploading files and their possible solutions.

Unexpected Not Found error with IIS

The following error indicates your file upload exceeds the server's configured maxAllowedContentLength:

HTTP 404.13 - Not Found

The request filtering module is configured to deny a request that exceeds the request content length.
The default setting is 30000000, which is approximately 28.6MB. The value can be customized by editing web.config:

<system.webserver>
  <security>
    <requestfiltering>
      <!-- This will handle requests up to 50MB -->
      <requestlimits maxallowedcontentlength="52428800"></requestlimits>
    </requestfiltering>
  </security>
</system.webserver>

Null Reference Exception with IFormFile

If your controller is accepting uploaded files using IFormFile but you find that the value is always null, confirm that your HTML form is specifying an enctype value of multipart/form-data. If this attribute is not set on the <form> element, the file upload will not occur and any bound IFormFile arguments will be null.

Best ASP.NET Core Hosting Recommendation

ASPHostPortal.com provides its customers with Plesk Panel, one of the most popular and stable control panels for Windows hosting, as free. You could also see the latest .NET framework, a crazy amount of functionality as well as Large disk space, bandwidth, MSSQL databases and more. All those give people the convenience to build up a powerful site in Windows server. ASPHostPortal.com offers ASP.NET hosting starts from $1/month only. They also guarantees 30 days money back and guarantee 99.9% uptime. If you need a reliable affordable ASP.NET Hosting, ASPHostPortal.com should be your best choice.



Entity Framework Core Tutorial

clock October 16, 2018 09:52 by author Kenny

Who doesn’t love a little bit of data access? Most line-of-business applications are built over some sort of data storage, and nine times out of ten it is a relational database. SQL has a long and distinguished pedigree dating back to some time in the 1980s. Unfortunately, relational data doesn’t match the way we use it in object-oriented languages. To solve this mismatch, we developed tools called object-relational mappers (ORMs).

In this article, we’ll look at one ORM in particular: Entity Framework Core.

A brief history of .NET ORMs

For many years in the .NET space, the king of these tools was NHibernate, which originated in the ALT.NET movement. One of my favorite ORMs from the same ALT.NET era was Subsonic created by Rob Connery. Microsoft, not wanting to be left out, created their own ORM called LINQ2SQL, which was supported only for a couple of years, but has the distinction of being the ORM used to create StackOverflow. Microsoft put in a much more serious effort with Entity Framework. As with a lot of Microsoft products, the early versions were inferior to the community-supported ones. But the technology rapidly improved, and by version 4 Entity Framework was, in my opinion, at least as good as NHibernate.

For a while, all was good in the Entity Framework world. But then came the great revolution that was ASP.NET Core and .NET Core. As part of this change, the Entity Framework team decided that the current EF code base would not support the ambitions of an updated ORM. Thes ambitions included being able to talk seamlessly to different storage backends such as MongoDB and Redis. Entity Framework Core was created. EF Core is now at version 2.1 and is the real deal. Let’s look at how to use it.

Why Entity Framework Core?

The .NET ecosystem contains a few actively maintained ORMs. Dapper comes to mind as the most readily used alternative. Dapper is a micro ORM that really just provides for the mapping from result sets into entities; it has no ability to generate schemas or get you out of writing SQL. EF supports all of this and can mean that you don’t need to write a single bit of SQL in your application. The queries that EF generates are very good and even quite readable, if you do need to drop to SQL to debug. When you need to get an application off the ground quickly, EF provides a low-friction path for data access.

Getting started

Before we dig too deep, let’s look at three of the major concepts in EF: the model, DbSet, and context. The most basic unit in Entity Framework Core is the model; you can think of a model as being a single row inside a relational database table. Models in EF are plain old CLR objects – that is to say, just classes with properties on them.

public class Ant {
    public Guid Id { get; set; }
    public string Name { get; set; }
    public int AgeInDays { get; set; }
    public string FavoriteAntGame { get; set; }
}

This class is a fine model. Notice that we have a property called Id on the model. While you don’t need to do this, it is a good idea to have an Id property that EF will automatically treat as the primary key for the table.

The next piece we need to know about is a DbSet. This is simply a collection that implements IQueryable in much the same way that a List does. There are some additional methods on the class that enable you to do updates you wouldn’t find on a simple IQueryable. DbSets are super powerful because you can work with them like you would any other collection. They can also be a source of performance problems because the abstraction away from the database allows for dramatically inefficient queries. You can think of DbSets as being tables in a database.

Finally, we have the DbContext that holds a number of DbSets which are related to each other. You can think of a DbContext as being the database proper or a schema within the database.

Setting up a data context

We’ve already started down the road of building a database around the concept of an ant hill so let’s go all in on that poor domain selection decision. Let’s add a couple of new entities to our the Ant we specified above. Perhaps a Queen and a Hive.

public class Queen
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public int AgeInDays { get; set; }
}
public class Hive
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public decimal LocationLatitude { get; set; }
    public decimal LocationLongitude { get; set; }
    public Queen Queen { get; set; }
    public IList<Ant> Ants { get; set; } = new List<Ant>();
}

These classes are, again, pretty simple. One thing to notice is that we have a Queen and a collection of Ants hanging off the Hive object. These provide some relationship information for EF and make using the data much easier from an object-oriented perspective.

To make use of EF we’ll pull these various items into a DataContext.

public class Context : DbContext
{
    public Context(DbContextOptions<Context> options) : base(options)
    {
    }
    public DbSet<Ant> Ants { get; set; }
    public DbSet<Hive> Hives { get; set; }
    public DbSet<Queen> Queens { get; set; }
}

If your application is a ASP.NET Core web application, then to start using the context you just need to register it in the services collection

services.AddDbContext<Context>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

This will use the default connection string from the configuration provider. In our example, we’re writing a command line application so we need to provide some of this configuration ourselves. To do so we can make use of the options builder

var optionsBuilder = new DbContextOptionsBuilder<Context>();
optionsBuilder.UseSqlServer("Server=(local);Database=hive_develop;Trusted_Connection=True;");
var context = new Context(optionsBuilder.Options);

In a normal scenario, you’ll want to get that connection string from a configuration source.

Keeping the context small

Frequently I see applications that keep dozens or hundreds (eeek!) of DbSets within a context. This is a bad plan because it encourages creating hyper-complex queries that span a lot of entities. You’re better to take a page out of the domain driven design book and treat each context as a bounded context. Julie Lerman, speaks of this in her data points article from way back in 2013.

Using the context

Now we’ve got a context, let’s start making use of it. The first thing we’ll want to do is lean on Entity Framework to create our actual database. This can be done as simply as calling:

await context.Database.EnsureCreatedAsync()

If we were to drill into the Hive table, we’d see that it has a foreign key relationship to Queen, which Entity Framework Core figured out by just looking at our classes. This is the simplest approach to building a database; however, for more complex and real-world scenarios, you’ll likely want to make use of a concept called Migrations. Migrations provide a mechanism for updating your database as the application evolves. They can be run outside of your application proper as part of a deployment pipeline, and also help when multiple developers might be making changes to the database at the same time.

Simple queries

One of the things that make Entity Framework Core such a powerful ORM is that it has first-class support for LINQ. This makes simple queries remarkably easy to execute. The DbSet in the context implements an interface called IQueryable, which allows you to chain function calls together to filter, project, sort, or any number of other things. Let’s try a few quick examples:

Get all the ants named Bob (a very popular name ant name):

context.Ants.Where(x => x.Name == "Bob")

You can also do compound queries where you provide multiple constraints. Here we want all the ants named Bob who are older than 30 days.

context.Ants.Where(x => x.Name == "Bob" && x.AgeInDays > 30)

Because all these queries are implemented using expressions you can build up queries and only have them execute when you request results from them. So, for example, we can build a search engine style query like so.

private async static Task<IEnumerable<Ant>> Search(Context context, int? age, string name, string game)
{
    var query = context.Ants as IQueryable<Ant>;
    if (age.HasValue)
        query = query.Where(x => x.AgeInDays == age);
    if (!String.IsNullOrEmpty(name))
        query = query.Where(x => x.Name == name);
    if (!String.IsNullOrEmpty(game))
        query = query.Where(x => x.FavoriteAntGame == game);
    return await query.ToListAsync();
}

This allows passing in a number of parameters, some of which may be null. As you can see, we build up a query in a highly readable and scalable fashion. The IQueryable may be passed around to any number of builder functions, each one of which stacks up some further criteria.

Of course, we can do more than just filter data using EF: data can be sorted, projected, or combined in a myriad of ways.

Complex queries

LINQ is a really nice domain-specific language for manipulating and querying objects, however, sometimes you have to relax the abstraction and get back to the relational model. If you find yourself building crazy queries that bend your mind with the complexity of the LINQ, then take a step back: you can drop to SQL to perform your queries.

This is done using the FromSql for queries:

context.Ants.FromSql<Ant>("select * from ants");

or using the ExecuteSqlCommandAsync:

context.Database.ExecuteSqlCommandAsync("delete from ants where name='Bob'");

Unfortunately, you must use a real entity for your SQL queries and you cannot use a projection. This was functionality that was available in EF and will hopefully resurface in EF Core at some point soon. The recommendation in the Entity Framework Core documentation is to use ADO.NET, like some sort of peasant from 2003. Instead, I’d suggest you make use of Dapper, which does support mapping arbitrary data to objects. It isn’t a fully fledged ORM, but it does have the advantage of being very fast and very tunable.

Updating data

Changing data retrieved from the context is really easy, thanks to the fact that all the entities used are tracked. If we wanted to load an Ant and then change the name, it is as simple as:

var ant = await context.Ants.FirstOrDefaultAsync(x => x.Id == id);
ant.Name = "Bob";
await context.SaveChangesAsync();

Performance tip: Async

You’ll notice that Entity Framework Core has a lot of asynchronous methods – they’re the ones ending in Async. These methods are generally a better option than the synchronous ones for applications that need to run multiple database queries at once. You should be aware that async does add some overhead, so it is not universally superior. Benchmarking is really the only solution.

Performance tip: No tracking

Entity Framework Core maintains a memory reference for every object retrieved from the database in order to know what has changed when writing records back. In many scenarios, especially web scenarios, there is no need to maintain this information because the entities you’re saving are rehydrated from an HTTP request. You can make EF Core much more efficient by setting no tracking:

var ants = context.Ants.AsNoTracking() .ToList();

Performance tip: Profiling

You can easily build queries in Entity Framework Core that seem reasonable, but end up being very costly when transformed to SQL. In order to watch the queries you’re making, there is no better tool than Prefix. You can use Prefix to spot common issues like n+1 problems or slow queries. Your users will be grateful that you’ve taken the time to install and run some profiling. And the best part is, Prefix is free.

Best ASP.NET Core Hosting Recommendation

ASPHostPortal.com provides its customers with Plesk Panel, one of the most popular and stable control panels for Windows hosting, as free. You could also see the latest .NET framework, a crazy amount of functionality as well as Large disk space, bandwidth, MSSQL databases and more. All those give people the convenience to build up a powerful site in Windows server. ASPHostPortal.com offers ASP.NET hosting starts from $1/month only. They also guarantees 30 days money back and guarantee 99.9% uptime. If you need a reliable affordable ASP.NET Hosting, ASPHostPortal.com should be your best choice.



ASP.NET Core Hosting - Using Swagger with ASP.NET Core

clock October 12, 2018 12:11 by author Kenny

Swagger is an auto-magically generated API documenting tool. It takes any standard Web API project and can generate amazing looking (And functioning) docs without a user having to write a single additional line of documentation. Best of all, it can be as simple as a 2 line setup, or as complex as adding additional info to every single API endpoint to explode the level of info inside Swagger.

Getting Started

For the purpose of this guide, I’m just going to be using the standard ASP.net Core Web API template when you create a new project from Visual Studio. But any existing API will work just fine too!

First off, install the following Nuget package from your package manager console.

Install-Package Swashbuckle.AspNetCore

Next in the ConfigureServices method of your startup.cs, add the following code to add the Swagger services to your application.

public void ConfigureServices(IServiceCollection services)
{
 services.AddMvc();
 
 services.AddSwaggerGen(swagger =>
 {
  swagger.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info { Title = "My First Swagger" });
 });
}

A couple of things to note here, firstly that inside the SwaggerGen lambda you can actually specify a few more details. As an example :

services.AddSwaggerGen(swagger =>
{
 swagger.DescribeAllEnumsAsStrings();
 swagger.DescribeAllParametersInCamelCase();
 swagger.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info { Title = "My First Swagger" });
});

Here we have said for any enum instead of using the integer value, use the string. And for all parameters can we please use CamelCase. The defaults usually suit most, but if there are specific things you are looking for your docs, you can probably find the setting here.

Secondly is obviously the Info object. Here you can specify things like the documentation author, title, and license among other things.

Head down to the Configure method of your Startup.cs.Add a call to “UseSwagger” and a call to “UseSwaggerUI” Both of these should come before the call to UseMVC.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
 app.UseSwagger();
 app.UseSwaggerUI(c =>
 {
  c.SwaggerEndpoint("/swagger/v1/swagger.json", "My First Swagger");
 });
 
 app.UseMvc();
}

And that’s it! Navigate your browser to https://localhost:{yourport}/swagger  to view your new API documentation.

If you don’t see anything, or it looks a bit odd, jump to the end of this article for a quick trouble shooting session!

XML Comments

The documentation that is auto generated is usually pretty damn good and if you are building a restful API, is usually enough to explain the functions of your API on their own. But there are times when the API needs a bit more explaining. For that, you can use XML Comments on your API action. For example :

/// <summary>
/// Gets a value by ID.
/// </summary>
/// <param name="id">The id of the value you wish to get.</param>
/// <returns></returns>
[HttpGet("{id}")]
public string Get(int id)
{
 return "value";
}

If you are using Visual Studio, you can type three forward slashes in a row and it will auto generate a skeleton set of comments for you. Most importantly is the summary and parameter descriptions that are free text. They are invaluable for being able to explain what an endpoint does and what input it expects.

Next you need to force your application to actually generate the XML data that Swagger can then read. Right click on your project in Visual Studio and select Properties. On the panel that opens up, select “Build” on the left hand side. You should see an option for “Output”, and a checkbox for “Xml documentation file”. Tick this box and the setting will be auto filled out for you.

Note that this setting is per build configuration. If you intend to use Swagger remotely (And therefore likely be built in Release mode before deploying), then you should change the Configuration setting up top on this panel to “Release” and then retick the documentation tickbox.

If you are not using Visual Studio, or you are just interested in how things work behind the scenes. Doing all of this just adds the following line to your csproj file.

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile>bin\Debug\netcoreapp2.0\SwaggerExample.xml</DocumentationFile>
</PropertyGroup>
Next you need to head back to the ConfigureServices method of your startup.cs and add a call to IncludeXmlComments in your Swagger configuration.
services.AddSwaggerGen(swagger =>
{
 swagger.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info { Title = "My First Swagger", Version = "v1" });
 swagger.IncludeXmlComments(Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "SwaggerExample.xml"));
});

Where SwaggerExample.xml is the xml file you set in your csproj/project configuration.

When you view Swagger again you should now see your XML comments displayed inside the documentation.

Up the top right is our description of our endpoint. And in the id row for our parameters, we also have a description value.

Describing API Response Codes

There may be times where your API returns a non “200” response code that you want to provide documentation for. For example an error of 400 if a particular parameter doesn’t fit certain requirements.

The first step is to decorate your actions with a “Produces” attribute that describes all the possible return codes your endpoint will give out. At the same time you can describe that for a given code, what model you will be returning at the same time. So for example if when you return an error 400, you return a particular class that describes the error, you can define that here.

[HttpGet("{id}")]
[ProducesResponseType(typeof(string), 200)]
[ProducesResponseType(404)]
[ProducesResponseType(400)]
public string Get(int id)
{
 return "value";
}

A quick note that you don’t need to specify the return of 200, that is implied, but it’s nice to add anyway. When you view this endpoint in swagger, the non 200 return codes are displayed at the bottom of the endpoint description.

While this lets you know that certain responses are expected, it doesn’t actually give you the reason why they would be returned. For that, we turn again to XML comments.

/// <summary>
/// Gets a value by ID.
/// </summary>
/// <param name="id">The id of the value you wish to get.</param>
/// <returns></returns>
/// <response code="200">Value returned</response>
/// <response code="404">Value was not able to be found</response>
/// <response code="400">Id was below 0</response>
[HttpGet("{id}")]
[ProducesResponseType(typeof(string), 200)]
[ProducesResponseType(404)]
[ProducesResponseType(400)]
public string Get(int id)
{
 return "value";
}

Now when we view this endpoint in Swagger again we have the descriptions next to the response codes.

Troubleshooting

I can’t see anything

Check that the nuget package  Microsoft.AspNetCore.StaticFiles is installed in the project. This is required by Swagger to run. If you are unsure, just try installing the package again, this has seriously fixed the issue for me before.

I’m using MVC Core

If you are use the “MVCCore” service rather than just plain MVC. Then you need to explicitly add the API Explorer services. Confused? Head to your ConfigureServices method in your startup.cs. If you see this :

services.AddMvc();

Then you are fine. However if you see this :

services.AddMvcCore();

Then you need to manually add the ApiExplorer service.

services.AddMvcCore().AddApiExplorer();

I’m not using “Attribute Routing”

Then Swagger won’t work for you. You must be using attribute routing to use Swagger.

Best ASP.NET Core Hosting Recommendation

ASPHostPortal.com provides its customers with Plesk Panel, one of the most popular and stable control panels for Windows hosting, as free. You could also see the latest .NET framework, a crazy amount of functionality as well as Large disk space, bandwidth, MSSQL databases and more. All those give people the convenience to build up a powerful site in Windows server. ASPHostPortal.com offers ASP.NET hosting starts from $1/month only. They also guarantees 30 days money back and guarantee 99.9% uptime. If you need a reliable affordable ASP.NET Hosting, ASPHostPortal.com should be your best choice.



ASP.NET Core Hosting - Using MailKit To Send And Receive Email In ASP.NET Core

clock October 5, 2018 06:09 by author Kenny

As commentators on this post have pointed out however, this has now been deprecated and the official documentation actually points you towards a very popular email library called “MailKit“. It’s open source, it’s super extensible, and it’s built on .NET Standard meaning that you can use the same code across .NET Full Framework, UWP and .NET Core projects.

Creating An Email Service

It’s always good practice that when you add in a new library, that you build an abstraction on top of it. If we take MailKit as an example, what if MailKit is later superceded by a better emailing library? Will we have to change references all over our code to reference this new library? Or maybe MailKit has to make a breaking change between versions, will we then have to go through our code fixing all the now broken changes? 

Another added bonus to creating an abstraction is that it allows us to map out how we want our service to look before we worry about implementation details. We can take a very high level view of sending an email for instance without having to worry about exactly how MailKit works. Because there is a lot of code to get through, I won’t do too much explaining at this point, we will just run through it. Let’s go!

First, let’s go ahead and create an EmailAddress class. This will have only two properties that describe an EmailAddress.

public class EmailAddress
{
 public string Name { get; set; }
 public string Address { get; set; }
}

Now we will need something to describe a simple EmailMessage. There are a tonne of properties on an email, for example attachments, CC, BCC, headers etc but we will break it down to the basics for now. Containing all of this within a class means that we can add extra properties as we need them later on.

public class EmailMessage
{
 public EmailMessage()
 {
  ToAddresses = new List<EmailAddress>();
  FromAddresses = new List<EmailAddress>();
 }
 
 public List<EmailAddress> ToAddresses { get; set; }
 public List<EmailAddress> FromAddresses { get; set; }
 public string Subject { get; set; }
 public string Content { get; set; }
}

Now we need to setup our email configuration. That’s our SMTP servers, ports, credentials etc. For this we will make a simple settings class to hold all of this. Since we are good programmers we will use an interface too!

public interface IEmailConfiguration
{
 string SmtpServer { get; }
 int SmtpPort { get; }
 string SmtpUsername { get; set; }
 string SmtpPassword { get; set; }
 
 string PopServer { get; }
 int PopPort { get; }
 string PopUsername { get; }
 string PopPassword { get; }
}
 
public class EmailConfiguration : IEmailConfiguration
{
 public string SmtpServer { get; set; }
 public int SmtpPort  { get; set; }
 public string SmtpUsername { get; set; }
 public string SmtpPassword { get; set; }
 
 public string PopServer { get; set; }
 public int PopPort { get; set; }
 public string PopUsername { get; set; }
 public string PopPassword { get; set; }
}

Now we actually need to load this configuration into our app. In your appsettings.json, you need to add a section at the root for email settings. It should look something like this :

{
  "EmailConfiguration": {
    "SmtpServer": "smtp.myserver.com",
    "SmtpPort": 465,
    "SmtpUsername": "smtpusername",
    "SmtpPassword": "smtppassword",
 
    "PopServer": "popserver",
    "PopPort": 995,
    "PopUsername": "popusername",
    "PopPassword" :  "poppassword"
  }
  ....Other settings here...
}

In the ConfigureServices method or your startup.cs, we can now pull out this configuration and load it into our app with a single line.

public void ConfigureServices(IServiceCollection services)
{
 services.AddMvc();
 services.AddSingleton<IEmailConfiguration>(Configuration.GetSection("EmailConfiguration").Get<EmailConfiguration>());
}

This allows us to inject our configuration class anywhere in our app.

The final piece of the puzzle is a simple email service that can be used to send and receive email. Let’s create an interface and an implementation that’s empty for now. The implementation should accept our settings object as a constructor.

public interface IEmailService
{
 void Send(EmailMessage emailMessage);
 List<EmailMessage> ReceiveEmail(int maxCount = 10);
}
 
public class EmailService : IEmailService
{
 private readonly IEmailConfiguration _emailConfiguration;
 
 public EmailService(IEmailConfiguration emailConfiguration)
 {
  _emailConfiguration = emailConfiguration;
 }
 
 public List<EmailMessage> ReceiveEmail(int maxCount = 10)
 {
  throw new NotImplementedException();
 }
 
 public void Send(EmailMessage emailMessage)
 {
  throw new NotImplementedException();
 }
}

Head back to our ConfigureServices method of our startup.cs to add in a final line to inject in our EmailService everywhere.

public void ConfigureServices(IServiceCollection services)
{
 services.AddMvc();
 services.AddSingleton<IEmailConfiguration>(Configuration.GetSection("EmailConfiguration").Get<EmailConfiguration>());
 services.AddTransient<IEmailService, EmailService>();
}

Phew! And we are done. If at this point we decided MailKit isn’t for us, we still have an email service that can swap in and out libraries as it needs to, and our calling application doesn’t need to worry about what’s going on under the hood. That’s the beauty of abstracting a library away!

Getting Started With MailKit

Getting started with MailKit is as easy as installing a Nuget package. Simply run the following from your Package Manager Console :

Install-Package MailKit

And hey presto! You now have access to MailKit in your application

Sending Email via SMTP With MailKit

Let’s head back to our email service class and fill out the “Send” method with the actual code to send an email via MailKit. The code to do this is below :

public void Send(EmailMessage emailMessage)
{
 var message = new MimeMessage();
 message.To.AddRange(emailMessage.ToAddresses.Select(x => new MailboxAddress(x.Name, x.Address)));
 message.From.AddRange(emailMessage.FromAddresses.Select(x => new MailboxAddress(x.Name, x.Address)));
 
 message.Subject = emailMessage.Subject;
 //We will say we are sending HTML. But there are options for plaintext etc.
 message.Body = new TextPart(TextFormat.Html)
 {
  Text = emailMessage.Content
 };
 
 //Be careful that the SmtpClient class is the one from Mailkit not the framework!
 using (var emailClient = new SmtpClient())
 {
  //The last parameter here is to use SSL (Which you should!)
  emailClient.Connect(_emailConfiguration.SmtpServer, _emailConfiguration.SmtpPort, true);
 
  //Remove any OAuth functionality as we won't be using it.
  emailClient.AuthenticationMechanisms.Remove("XOAUTH2");
 
  emailClient.Authenticate(_emailConfiguration.SmtpUsername, _emailConfiguration.SmtpPassword);
 
  emailClient.Send(message);
 
  emailClient.Disconnect(true);
 }
  
}

The comments should be pretty self explanatory, but let’s quickly run through it.

  • You can send clear text or HTML emails depending on the “TextFormat” you use when creating your message body
  • MailKit has named it’s Smtp class “SmtpClient” which is the same as the framework class. Be careful if you are using Resharper and the like that when you click “Add Reference” you are adding the correct reference.
  • You should choose to use SSL whenever available when connecting to the SMTP Server

Because we built out our EmailService, EmailMessage and EmailConfiguration classes earlier, they are all ready to be used immediately!

Receiving Email via POP With MailKit

And now the code to receive email via POP.

public List<EmailMessage> ReceiveEmail(int maxCount = 10)
{
 using (var emailClient = new Pop3Client())
 {
  emailClient.Connect(_emailConfiguration.PopServer, _emailConfiguration.PopPort, true);
 
  emailClient.AuthenticationMechanisms.Remove("XOAUTH2");
 
  emailClient.Authenticate(_emailConfiguration.PopUsername, _emailConfiguration.PopPassword);
 
  List<EmailMessage> emails = new List<EmailMessage>();
  for(int i=0; i < emailClient.Count && i < maxCount; i++)
  {
   var message = emailClient.GetMessage(i);
   var emailMessage = new EmailMessage
   {
    Content = !string.IsNullOrEmpty(message.HtmlBody) ? message.HtmlBody : message.TextBody,
    Subject = message.Subject
   };
   emailMessage.ToAddresses.AddRange(message.To.Select(x => (MailboxAddress)x).Select(x => new EmailAddress { Address = x.Address, Name = x.Name }));
   emailMessage.FromAddresses.AddRange(message.From.Select(x => (MailboxAddress)x).Select(x => new EmailAddress { Address = x.Address, Name = x.Name }));
  }
 
  return emails;
 }
}

Again, all rather straight forward.

While we only retrieve a few basic details about the email message, the actual MailKit email object has a tonne of data you can inspect including headers, CC addresses, etc. Extend as you need to!

I Got Exception XYZ

SMTP can sometimes be a bit tricky getting right in terms of SSL, TLS, and ports. Worse yet, the exception messages are often either cryptic, or start pushing you in the completely wrong direction. I created another article here, that should cover any sort of exception you might get when using this code.

Free SMTP Server

It’s worth mentioning that if you are a hobbyist with your own website and want to just send a few emails every now and again under your own domain. A great solution that I use for this very blog is MailGun. It has a great free plan that for most people will be more than enough, but also paid plans for when you really need to start sending a lot of email.

Best ASP.NET Core Hosting Recommendation

ASPHostPortal.com provides its customers with Plesk Panel, one of the most popular and stable control panels for Windows hosting, as free. You could also see the latest .NET framework, a crazy amount of functionality as well as Large disk space, bandwidth, MSSQL databases and more. All those give people the convenience to build up a powerful site in Windows server. ASPHostPortal.com offers ASP.NET hosting starts from $1/month only. They also guarantees 30 days money back and guarantee 99.9% uptime. If you need a reliable affordable ASP.NET Hosting, ASPHostPortal.com should be your best choice.

 



ASP.NET Core Hosting - ASPHostPortal :: API Project ASP.NET Core

clock September 25, 2018 09:26 by author Jervis

In this post, we are going to write about what we consider to be the best practices while developing the .NET Core Web API project. How we can make it better and how to make it more maintainable.

Startup Class and the Service Configuration

In the Startup class, there are two methods: the ConfigureServices method for registering the services and the Configure method for adding the middleware components to the application’s pipeline.

So, the best practice is to keep the ConfigureServices method clean and readable as much as possible. Of course, we need to write the code inside that method to register the services, but we can do that in more readable and maintainable way by using the Extension methods.

For example, let’s look at the wrong way to register CORS:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials());
    });
}    

Even though this way will work just fine, and will register CORS without any problem, imagine the size of this method after registering dozens of services.

That’s not readable at all.

The better way is to create an extension class with the static method: 

public static class ServiceExtensions
{
    public static void ConfigureCors(this IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy",
                builder => builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());
        });
    }
}

And then just to call this extended method upon the IServiceCollection type:

public void ConfigureServices(IServiceCollection services)
{
    services.ConfigureCors();
}

Project Organization

We should always try to split our application into smaller projects. That way we are getting the best project organization and separation of concerns (SoC). The business logic related to our entities, contracts, accessing the database, logging messages or sending an email message should always be in a separate .NET Core Class Library project.

Every small project inside our application should contain a number of folders to organize the business logic.

Here is just one simple example how a complete project should look like: 

Environment Based Settings

While we develop our application, that application is in the development environment. But as soon as we publish our application it is going to be in the production environment. Therefore having a separate configuration for each environment is always a good practice.

In .NET Core, this is very easy to accomplish.

As soon as we create the project, we are going to get the appsettings.json file and when we expand it we are going to see the appsetings.Development.json file:

All the settings inside this file are going to be used for the development environment.

We should add another file appsettings.Production.json, to use it in a production environment:

The production file is going to be placed right beneath the development one.

Data Access Layer

In many examples and different tutorials, we may see the DAL implemented inside the main project and instantiated in every controller. This is something we shouldn’t do.

When we work with DAL we should always create it as a separate service. This is very important in the .NET Core project because when we have DAL as a separate service we can register it inside the IOC (Inversion of Control) container. The IOC is the .NET Core’s built-in feature and by registering a DAL as a service inside the IOC we are able to use it in any controller by simple constructor injection:

public class OwnerController: Controller
{
    private IRepository _repository;
 
    public OwnerController(IRepository repository)
    {
        _repository = repository;
    }
}

Controllers

The controllers should always be as clean as possible. We shouldn’t place any business logic inside it.

So, our controllers should be responsible for accepting the service instances through the constructor injection and for organizing HTTP action methods (GET, POST, PUT, DELETE, PATCH…): 

public class OwnerController: Controller
{
    private ILoggerManager _logger;
    private IRepository _repository;
 
    public OwnerController(ILoggerManager logger, IRepository repository)
    {
        _logger = logger;
        _repository = repository;
    }
 
    [HttpGet]
    public IActionResult GetAllOwners()
    {           
    }
 
    [HttpGet("{id}", Name = "OwnerById")]
    public IActionResult GetOwnerById(Guid id)
    {          
    }
 
    [HttpGet("{id}/account")]
    public IActionResult GetOwnerWithDetails(Guid id)
    {
    }
 
    [HttpPost]
    public IActionResult CreateOwner([FromBody]Owner owner)
    {       
    }
 
    [HttpPut("{id}")]
    public IActionResult UpdateOwner(Guid id, [FromBody]Owner owner)
    {         
    }
 
    [HttpDelete("{id}")]
    public IActionResult DeleteOwner(Guid id)
    {        
    }
}

Actions

Our actions should always be clean and simple. Their responsibilities include handling HTTP requests, validating models, catching errors and returning responses: 

[HttpPost]
public IActionResult CreateOwner([FromBody]Owner owner)
{
    try
    {
        if (owner.IsObjectNull())
        {
            return BadRequest("Owner object is null");
        }
 
        if (!ModelState.IsValid)
        {
            return BadRequest("Invalid model object");
        }
 
        _repository.Owner.CreateOwner(owner);
 
        return CreatedAtRoute("OwnerById", new { id = owner.Id }, owner);
    }
    catch (Exception ex)
    {
        _logger.LogError($"Something went wrong inside the CreateOwner action: {ex}");
        return StatusCode(500, "Internal server error");
    }
}

Our actions should have IActionResult as a return type in most of the cases (sometimes we want to return a specific type or a JsonResult…). That way we can use all the methods inside .NET Core which returns results and the status codes as well.

The most used methods are:

  • OK => returns the 200 status code
  • NotFound => returns the 404 status code
  • BadRequest => returns the 400 status code
  • NoContent => returns the 204 status code
  • Created, CreatedAtRoute, CreatedAtAction => returns the 201 status code
  • Unauthorized => returns the 401 status code
  • Forbid => returns the 403 status code
  • StatusCode => returns the status code we provide as input 

Handling Errors Globally

In the example above, our action has its own try-catch block. This is very important because we need to handle all the errors (that in another way would be unhandled) in our action method. Many developers are using try-catch blocks in their actions and there is absolutely nothing wrong with that approach. But, we want our actions to be clean and simple, therefore, removing try-catch blocks from our actions and placing them in one centralized place would be an even better approach.

.NET Core gives us an opportunity to implement exception handling globally with a little effort by using built-in and ready to use middleware. All we have to do is to add that middleware in the Startup class by modifying the Configure method:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 {
     app.UseExceptionHandler(config =>
     {
         config.Run(async context =>
         {
             context.Response.StatusCode = 500;
             context.Response.ContentType = "application/json";
 
             var error = context.Features.Get<IExceptionHandlerFeature>();
             if (error != null)
             {
                 var ex = error.Error;
 
                 await context.Response.WriteAsync(new ErrorModel()
                 {
                     StatusCode = 500,
                     ErrorMessage = ex.Message
                 }.ToString(); //ToString() is overridden to Serialize object
             }
         });
     });
 
     app.UseMvc();
}

We can even write our own custom error handlers by creating custom middleware: 

public class CustomExceptionMiddleware
{
    //constructor and service injection
 
    public async Task Invoke(HttpContext httpContext)
    {
        try
        {
            await _next(httpContext);
        }
        catch (Exception ex)
        {
            _logger.LogError("Unhandled exception ...", ex);
            await HandleExceptionAsync(httpContext, ex);
        }
    }
   
    //additional methods
}

After that we need to register it and add it to applications pipeline: 

public static IApplicationBuilder UseCustomExceptionMiddleware(this IApplicationBuilder builder)
{
    return builder.UseMiddleware<CustomExceptionMiddleware>();
}

Using ActionFilters to Remove Duplicated Code

Filters in ASP.NET Core allows us to run some code prior to or after the specific stage in a request pipeline. Therefore, we can use them to execute validation actions that we need to repeat in our action methods.

When we handle a PUT or POST request in our action methods, we need to validate our model object as we did in the Actions part of this article. As a result, that would cause the repetition of our validation code, and we want to avoid that (Basically we want to avoid any code repetition as much as we can).

We can do that by using the ActionFilters. Instead of validation code in our action: 

if (!ModelState.IsValid)
{
  // bad request and logging logic
}

We can create our filter: 

public class ModelValidationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            context.Result = new BadRequestObjectResult(context.ModelState); // returns 400 with error
        }
    }
}

And register it in the Startup class in the ConfigureServices method: 

services.AddScoped<ModelValidationAttribute>();

Now, we can use that filter with our action methods.

Microsoft.AspNetCore.All Meta-Package

This meta-package contains all of the AspNetCore packages, EntityFrameworkCore packages, SignalR package (from version 2.1) and the supporting packages required for running the framework. It is pretty convenient when starting a new project because we don’t have to manually install and reference all the packages we might need.

Of course, your machine needs to have the .NET Core runtime installed on it in order to use the AspNetCore meta-package.

Routing

In the .NET Core Web API projects, we should use Attribute Routing instead of Conventional Routing. That’s because Attribute Routing helps us match the route parameter names with the actual parameters inside the action methods. Another reason is the description of the route parameters. It is more readable when we see the parameter with the name “ownerId” than just “id”.

We can use the [Route] attribute on top of the controller and on top of the action itself: 

[Route("api/[controller]")]
public class OwnerController: Controller
{
     [Route("{id}")]
     [HttpGet]
     public IActionResult GetOwnerById(Guid id)
     {
           
     } 
}

There is another way to create routes for the controller and actions: 

[Route("api/owner")]
public class OwnerController: Controller
{
     [HttpGet("{id}")]
     public IActionResult GetOwnerById(Guid id)
     {
           
     } 
}

There are different opinions which way is better, but we would always recommend the second way, and this is something we always use in our projects.

When we talk about the routing we need to mention the route naming convention. We can use descriptive names for our actions, but for the routes/endpoints, we should use NOUNS and not VERBS.

The few wrong examples: 

[Route("api/owner")]
public class OwnerController : Controller
{
    [HttpGet("getAllOwners")]
    public IActionResult GetAllOwners()
    {
    }
 
    [HttpGet("getOwnerById/{id}"]
    public IActionResult GetOwnerById(Guid id)
    {       
    }
}

The good examples: 

[Route("api/owner")]
public class OwnerController : Controller
{
    [HttpGet]
    public IActionResult GetAllOwners()
    {
    }
 
    [HttpGet("{id}"]
    public IActionResult GetOwnerById(Guid id)
    {         
    }
}

Logging

If we plan to publish our application to production, we should have a logging mechanism in place. Log messages are very helpful when figuring out how our software behaves in a production.

.NET Core has its own logging implementation by using the ILoggerinterface. It is very easy to implement it by using Dependency Injection feature: 

public class TestController: Controller
{
    private readonly ILogger _logger;
 
    public TestController(ILogger<TestController> logger)
    {
        _logger = logger;
    }
}

Then in our actions, we can utilize various logging levels by using the _logger object.

.NET Core supports logging API that works with a variety of logging providers. Therefore, we may use different logging providers to implement our own logging logic inside our project.

The NLog is the great library to use for implementing our own custom logging logic. It is extensible, supports structured logging and very easy to configure. We can log our messages in the console window, files or even database. 

CryptoHelper

We won’t talk about how we shouldn’t store the passwords in a database as a plain text and how we need to hash them due to security reasons. That’s out of the scope of this article. There are various hashing algorithms all over the internet, and there are many different and great ways to hash a password.

But if need the library that provides support to the .NET Core’s application and that is easy to use, the CryptoHelper is quite a good library.

This library is available for installation through the NuGet and its usage is quite simple:

using CryptoHelper;
 
// Method for hashing the password
public string HashPassword(string password)
{
    return Crypto.HashPassword(password);
}
 
// Method to verify the password hash against the given password
public bool VerifyPassword(string hash, string password)
{
    return Crypto.VerifyHashedPassword(hash, password);
}

Content Negotiation

By default .NET Core Web API returns a JSON formatted result. In most of the cases, that’s all we need.

But what if the consumer of our Web API wants another response format, like XML for example?

For that, we need to create a server configuration to format our response in the desired way: 

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(config =>
    {
        // Add XML Content Negotiation
        config.RespectBrowserAcceptHeader = true;
        config.InputFormatters.Add(new XmlSerializerInputFormatter());
        config.OutputFormatters.Add(new XmlSerializerOutputFormatter());
    });
}

Sometimes the client may request a format that is not supported by our Web API and then the best practice is to respond with the status code 406 Not Acceptable. That can be configured inside our ConfigureServices method as well: 

config.ReturnHttpNotAcceptable = true;

We can create our own custom format rules as well.

Using JWT

JSON Web Tokens (JWT) are becoming more popular by the day in the web development. It is very easy to implement JWT Authentication is very easy to implement due to the .NET Core’s built-in support. JWT is an open standard and it allows us to transmit the data between a client and a server as a JSON object in a secure way.

We can configure the JWT Authentication in the ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
     services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
       .AddJwtBearer(options =>
       {
          options.TokenValidationParameters = new TokenValidationParameters
          {
             //Configuration in here
          };
       });
}

In order to use it inside the application, we need to invoke this code in the Configure method:

app.UseAuthentication();

We may use JWT for the Authorization part as well, by simply adding the role claims to the JWT configuration 

Conclusion

In this article, our main goal was to familiarize you with the best practices when developing a Web API project in .NET Core. Some of those could be used in other frameworks as well, therefore, having them in mind is always helpful.

If you find that something is missing from the list, don’t hesitate to add it in a comment section.

Thank you for reading the article and I hope you found something useful in it.



ASP.NET Core Hosting - Using Layered Architectures In ASP.NET

clock September 7, 2018 11:57 by author Kenny

One approach to designing Web applications is to focus on clearly defined layers of the application’s architecture. This approach is similar to the way an architect designs a building. If you’ve ever seen detailed construction plans for a skyscraper, you know the construction plans include separate blueprints for the foundation, frame, roof, plumbing, electrical, and other floors of the building.

With a layered architecture, specialists can design and develop the “floors” — called layers — independently, provided that the connections between the layers (the interfaces) are carefully thought out.

The layers should be independent of one another, as much as possible. Among other things, that means heeding a few must-dos and shalt-nots:

Each layer must have a clearly defined focus. To design the layers properly, you must clearly spell out the tasks and responsibilities of each layer.

Layers should mind their own business. If one layer is responsible for user interaction, only that layer is allowed to communicate with the user. Other layers that need to get information from the user must do so through the User Interface Layer.

Clearly defined protocols must be set up for the layers to interact with one another. Interaction between the layers occurs only through these protocols.

Note that the layers are not tied directly to any particular application. For example, an architecture might work equally well for an online ordering system and for an online forum. As a result, layered architecture has nothing to do with the ERDs that define a database or the Data Flow Diagrams that define how the data flows within the application. It’s a separate structure.

HOW MANY LAYERS?

There are several common approaches to application architecture that vary depending on the number of layers used. One common scheme is to break the application into two layers:

Application Layer: The design of the user interface and the implementation of business policies are handled in this layer. This layer may also handle transaction logic — the code that groups database updates into transactions and ensures that all updates within a transaction are made consistently.

Data Access Layer: The underlying database engine that supports the application. This layer is responsible for maintaining the integrity of the database. Some or all the transaction logic may be implemented in this layer.

In the two-layer model, the Application Layer is the ASP.NET Web pages that define the pages presented to the user as well as the code-behind files that implement the application’s logic. The Data Access Layer is the database server that manages the database, such as Microsoft SQL Server or Oracle.

Note that ASP.NET 2.0 doesn’t require that you place the application’s logic code in a separate code-behind file. Instead, you can intersperse the logic code with the presentation code in the same file. However, it’s almost always a good idea to use separate code-behind files to separate the application’s logic from its presentation code. All of the applications presented in this book use separate code-behind files.

The division between the Application and Data Access layers isn’t always as clear-cut as it could be. For performance reasons, transaction logic is often shifted to the database server (in the form of stored procedures), and business rules are often implemented on the database server with constraints and triggers. Thus, the database server often handles some of the application logic.

If this messiness bothers you, you can use a three-layer architecture, which adds an additional layer to handle business rules and policies:

Presentation Layer: This layer handles the user interface.

Business Rules Layer: This layer handles the application’s business rules and policies. For example, if a sales application grants discounts to certain users, the discount policy is implemented in this layer.

Data Access Layer: The underlying database model that supports the application.

Creating a separate layer for business rules enables you to separate the rules from the database design and the presentation logic. Business rules are subject to change. By placing them in a separate layer, you have an easier task of changing them later than if they’re incorporated into the user interface or database design.

MODEL-VIEW-CONTROLLER

Another common model for designing Web applications is called Model-View-Controller (MVC). In this architecture, the application is broken into three parts:

Model: The model is, in effect, the application’s business layer. It usually consists of objects that represent the business entities that make up the application, such as customers and products.

View: The view is the application’s user interface. In a Web application, this consists of one or more HTML pages that define the look and feel of the application.

Controller: The controller manages the events processed by the application. The events are usually generated by user-interface actions, such as the user clicking a button or selecting an item from a drop-down list.

In a typical ASP.NET application, the .aspx file implements the view; the model and controller functions are combined and handled by the code-behind file. Thus, the code-behind file can be thought of as the model-controller.

Best ASP.NET Hosting Recommendation

ASPHostPortal.com provides its customers with Plesk Panel, one of the most popular and stable control panels for Windows hosting, as free. You could also see the latest .NET framework, a crazy amount of functionality as well as Large disk space, bandwidth, MSSQL databases and more. All those give people the convenience to build up a powerful site in Windows server. ASPHostPortal.com offers ASP.NET hosting starts from $1/month only. They also guarantees 30 days money back and guarantee 99.9% uptime. If you need a reliable affordable ASP.NET Hosting, ASPHostPortal.com should be your best choice.



Cheap ASP.NET 4.5 Hosting

We’re a company that works differently to most. Value is what we output and help our customers achieve, not how much money we put in the bank. It’s not because we are altruistic. It’s based on an even simpler principle. "Do good things, and good things will come to you".

Success for us is something that is continually experienced, not something that is reached. For us it is all about the experience – more than the journey. Life is a continual experience. We see the Internet as being an incredible amplifier to the experience of life for all of us. It can help humanity come together to explode in knowledge exploration and discussion. It is continual enlightenment of new ideas, experiences, and passions


Author Link

 photo ahp banner aspnet-01_zps87l92lcl.png

 

Corporate Address (Location)

ASPHostPortal
170 W 56th Street, Suite 121
New York, NY 10019
United States

Tag cloud

Sign in