User Secrets

Email with ASP.NET Core Using Mailgun

Sending emails from ASP.NET Core using Mailgun is a topic I covered in this post almost a year ago. The previous post was before ASP.NET Core hit 1.0 and I didn’t save or upload the code to GitHub. Based on the comments on the post I decided to redo the post using the current version of ASP.NET.

Starting point

For this post, I created a new ASP.NET Core Web Application targeting .NET Core using Individual User Accounts for authentication. The project before any changes for email can be found here.

UI and Controller change to support email

The project template comes with all the UI and controller functions need to support email, but they are commented out. The following is going to walk through uncommenting the proper code.

Account controller

Starting with the Register function the code to send a confirmation email needs to be uncommented and the existing call to _signInManager.SignInAsync should be commented out to keep a user from being signed in before their email address has been confirmed. The following is after the changes.

var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Action("ConfirmEmail", "Account", 
                             new { userId = user.Id, code = code }, 
                             protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
   $"Please confirm your account by clicking this link: 
     <a href='{callbackUrl}'>link</a>");
//await _signInManager.SignInAsync(user, isPersistent: false);

Next, in the Login function add a check to verify a user’s account has been confirmed before allowing them to sign in. The new code starts with var user = await _userManager.FindByNameAsync(model.Email); the code above it is just to provide context.

 public async Task<IActionResult> Login(LoginViewModel model, 
                                        string returnUrl = null)
 {
      ViewData["ReturnUrl"] = returnUrl;
      if (ModelState.IsValid)
      {
          var user = await _userManager.FindByNameAsync(model.Email);
          if (user != null)
          {
              if (!await _userManager.IsEmailConfirmedAsync(user))
              {
                  ModelState.AddModelError(string.Empty, 
                              "You must have a confirmed email to log in.");
                  return View(model);
              }
          }

Finally, in the ForgotPassword function uncomment the following to enable sending the user a password reset link.

var code = await _userManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = Url.Action("ResetPassword", "Account", 
                             new { userId = user.Id, code = code }, 
                             protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Reset Password",
   $"Please reset your password by clicking here: <a          
     href='{callbackUrl}'>link</a>");
return View("ForgotPasswordConfirmation");
Forgot password view

To enabled the UI related to sending an email for a forgotten password open ForgotPassword.cshtml found in the Views/Account/ directory and uncomment the following.

<form asp-controller="Account" asp-action="ForgotPassword" 
      method="post" class="form-horizontal">
    <h4>Enter your email.</h4>
    <hr />
    <div asp-validation-summary="All" class="text-danger"></div>
    <div class="form-group">
        <label asp-for="Email" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input asp-for="Email" class="form-control" />
            <span asp-validation-for="Email" class="text-danger"></span>
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
             <button type="submit" 
                     class="btn btn-default">Submit</button>
        </div>
    </div>
</form>

Warning for sites with existing users

The changes above will cause issues for any existing users since they will not have completed the email confirmation step keeping them from being able to log in or reset passwords. Manually marking existing users as confirmed can be done by updating the EmailConfirmed bit field to true in the AspNetUsers table.

Mailgun

Mailgun is an email service run by Rackspace that provides a simple API for sending emails. The free level of the service allows up to 10k emails to be sent a month.

You can sign up for an account here. Once logged in go to the Domains section.

Next, select your domain should only be one if you are on a new account. This will take you to a screen that looks like the following some of which will be needed to connect with the Mailgun API. I took the time to replace my information with a fake version so this screen shot could be referenced using the values from the screenshot for the rest of the post.

Configuration

Settings class

In order to hold and load Mailgun email related settings add a new EmailSettings class. In the sample project, this class can be found in the Configuration directory. The following is the full contents of the file.

public class EmailSettings
{
    public string ApiKey { get; set; }
    public string ApiBaseUri { get; set; }
    public string RequestUri { get; set; }
    public string From { get; set; }
}
User secrets introduction

User secrets is a concept in ASP.NET Core used to set configuration items and have them stored outside of the project so they will be excluded from version control. They are a great way to store private API key and related items which is why they will be used to store our Mailgun configuration items. I will be coving the basics here, but for a more detail explanation check out the official docs on the topic of app secrets.

Setting user secrets

In the Solution Explorer right-click on the project and select Manage User Secrets.

This will open the secrets.json file which will be used to store secrets related to the select project. Keep in mind this file is stored in your user directory in an unencrypted way so don’t view it as a secured store.

Based on the screenshot above from Mailgun’s domain detail page the json file would look like the following. The RequestUri is the only setting not pulled from the domain settings above and would just need fakesandbox replaced with the sandbox ID for your domain.

{
  "EmailSettings": {
    "ApiKey": "api:key-fakeapikey",
    "ApiBaseUri": "https://api.mailgun.net/v3/",
    "RequestUri": "fakesandbox.mailgun.org/messages",
    "From": "[email protected]"
  }
}
Loading user secrets in Startup

In the ConfigureServices function of the Startup class the EmailSettings section of our user secrets can be loaded and made available via the dependency injection system using the following line of code.

services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));

Not that user secrets are only meant to be used for development and for a production build of the applications the settings would need to be moved to a different location such as environment variables or Azure Key Vault.

Using Mailgun to send email

Not that the application has the email sending portion of the UI enabled the SendEmailAsync function of the AuthMessageSender class needs to be implemented. The class can be found in the MessageServices.cs file of the Services directory.

Injection of email settings

The first change needed is to add a class level variable to store email settings and to add a constructor that will allow the email setting to be injected.

private readonly EmailSettings _emailSettings;

public AuthMessageSender(IOptions<EmailSettings> emailOptions)
{
    _emailSettings = emailOptions.Value;
}
Sending an email

The body of the SendEmailAsync function is where the call to Mailgun’s API will be made using the email setting injected via the class’s constructor. The following is the full body of the function.

using (var client = new HttpClient { BaseAddress = 
                                     new Uri(_emailSettings.ApiBaseUri) })
{
    client.DefaultRequestHeaders.Authorization = 
      new AuthenticationHeaderValue("Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes(_emailSettings.ApiKey)));

    var content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("from", _emailSettings.From),
        new KeyValuePair<string, string>("to", email),
        new KeyValuePair<string, string>("subject", subject),
        new KeyValuePair<string, string>("html", message)
    });

    await client.PostAsync(_emailSettings.RequestUri, 
                           content).ConfigureAwait(false);
}

The Mailgun API key is sent as an authentication header value with the rest of the parameters being sent via form URL encoded content. Finally, the Request URI from the email settings is used to send the post request to Mailgun.

If you just need to send a plain text instead of HTML the “html” key can be replaced with “text”.

Authorized recipients required for test domain

When using Mailgun with the default test domain note that only emails addressed to Authorized Recipients will be delivered. To add a recipient click Authorized Recipients button on Mailgun’s Domains page.

This will take you to the Authorized Recipients page where you can use the Invite New Recipient button to add a recipient.

Enter the email address you want to add and click the Send Invite button. After the email address is confirmed mail to that address will be delivered. Keep in mind this is only for test accounts and doesn’t have to be done when being used with a real domain.

Using logs to verify state of emails

During my testing, I wasn’t seeing emails come through and I thought something was wrong with my code, but it turned out that Mailgun was getting the request to send the mail they just hadn’t be processed yet. The Logs section of your Mailgun account is helpful for determining if they are getting your request to send an email or not.

As you can see in the screenshot the email request was accepted, but not yet delivered. It was 10 minutes later before the email was actually delivered. I am not sure if this delay is just for test domains or if would apply to live ones as well.

Other Email Options

Mailgun is obviously not the only option for sending emails. This post from Mashape lists 12 API providers. In addition SMTP is also an option which this post by Steve Gordon covers.

Wrapping up

The code finished code that goes with this post can be found here. Thank you to all the commenters on the original post for stepping in when I didn’t have all the answer or code available.

Email with ASP.NET Core Using Mailgun Read More »

SMS using Twilio Rest API in ASP.NET Core

A couple of weeks ago I went over using email in ASP.NET Core which left the provided MessageService class half implemented.  This post is going to cover the implementation of the other MessageService function that is used to send SMS as part of two-factor authentication.

View

In Views/Manage/Index.cshtml uncomment the following to enable the UI bit associated with phone numbers.

@(Model.PhoneNumber ?? "None")
    @if (Model.PhoneNumber != null)
    {
        <br />
        <text>[&nbsp;&nbsp;<a asp-controller="Manage" asp-action="AddPhoneNumber">Change</a>&nbsp;&nbsp;]</text>
        <form asp-controller="Manage" asp-action="RemovePhoneNumber" method="post" role="form">
            [<button type="submit" class="btn-link">Remove</button>]
        </form>
    }
    else
    {
        <text>[&nbsp;&nbsp;<a asp-controller="Manage" asp-action="AddPhoneNumber">Add</a>&nbsp;&nbsp;]</text>
    }

And this as well.

@if (Model.TwoFactor)
    {
        <form asp-controller="Manage" asp-action="DisableTwoFactorAuthentication" method="post" class="form-horizontal" role="form">
            Enabled [<button type="submit" class="btn-link">Disable</button>]
        </form>
    }
    else
    {
        <form asp-controller="Manage" asp-action="EnableTwoFactorAuthentication" method="post" class="form-horizontal" role="form">
            [<button type="submit" class="btn-link">Enable</button>] Disabled
        </form>
    }

Twilio

I spend a lot of time trying to find a services that allows sending of SMS for free and had zero luck. I ended up going with  Twilio as they do provide free messaging with their trial account. The usage section of the web site will make it looking like you will be changed, but that is just to provide an idea of what the service would cost and will not actually be charged.

Storing Configuration

Just as a couple of weeks ago for EmailSetting I created a SmsSettings class that will be loaded from user secrets in the StartUp class of the application. For more details on general configuration in ASP.NET Core check out this post and then this post for more details on user secrets. The following is my SMS settings class.

public class SmsSettings
{
    public string Sid { get; set; }
    public string Token { get; set; }
    public string BaseUri { get; set; }
    public string RequestUri { get; set; }
    public string From { get; set; }
}

And this is the config file looks like with the curly braces needed to be replace with values from your Twilio account. For example if your Twilio phone number was 15554447777 then the from line would be: “From”: “+15554447777”

{
  "SmsSettings": {
    "Sid": "{TwilioAccountSid}",
    "Token": "{TwilioAuthToken}",
    "BaseUri": "https://api.twilio.com",
    "RequestUri": "/2010-04-01/Accounts/{TwilioAccountSid}/Messages.json",
    "From": "+{TwilioPhoneNumber}"
  }
}

Then in ConfigureServices function of Startup.cs add a reference to the SmsSettings class to make it available using dependency injection.

services.Configure<SmsSettings>(Configuration.GetSection("SmsSettings"));

Message Services

In Services/MessageService.cs there is an empty implementation for sending SMS base on ISmsSender which defines a single SendSmsAsync function which is called when the application wants to send a SMS.

Add a constructor to the class if it doesn’t already have one so that the SmsSettings can be injected by the framework and add a field to store the settings in. I have removed the email related items from the constructor but you can look at this post if you want to include the email related bits a well.

private readonly SmsSettings _smsSettings;

public AuthMessageSender(IOptions<SmsSettings> smsSettings)
{
    _smsSettings = smsSettings.Value;
}

Then the SendSmsAsync function which uses the HttpClient with basic authentication and form url encoded content to make a post request to the Twilio API looks like the following.

public async Task SendSmsAsync(string number, string message)
{
    using (var client = new HttpClient { BaseAddress = new Uri(_smsSettings.BaseUri) })
    {
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
            Convert.ToBase64String(Encoding.ASCII.GetBytes($"{_smsSettings.Sid}:{_smsSettings.Token}")));

        var content = new FormUrlEncodedContent(new[]
        {
            new KeyValuePair<string, string>("To",$"+{number}"),
            new KeyValuePair<string, string>("From", _smsSettings.From),
            new KeyValuePair<string, string>("Body", message)
        });

        await client.PostAsync(_smsSettings.RequestUri, content).ConfigureAwait(false);
    }
}

Now you application is capable of sending SMS.

ASP.NET Docs

As I was writing this I came across Rick Anderson’s post in the official docs that covers two-factor authentication. I highly recommend you read Rick’s post as he covers the UI portion in more depth than I did. Another note Rick is using the Twilio helper client were I am using the HttpClient in order to maintain dnxcore50 compatibility.

SMS using Twilio Rest API in ASP.NET Core Read More »

Emails using Mailgun in ASP.NET Core

Updated version of this post can be found here.

At last month’s Nashville .Net Users Group meeting Michael McCann when over some of the aspects of ASP.NET’s membership provider (non-core version). One of the things he talked about was enabling email as part of the user sign up process and for use in password recovery. This post is going to cover the same emailing aspect but in ASP.NET core using mailgun to actually send emails.

Account Controller

In the account controller most of the code needed is already present and just needs to be uncommented. In the Register function uncomment the following which will send the user an email asking that the address be confirmed. This of course stops users from signing up with email addresses they don’t actually have access to.

var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Action("ConfirmEmail", 
                             "Account", 
                             new { userId = user.Id, code = code }, 
                             protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
  "Please confirm your account by clicking this link: <a href=\"" + callbackUrl + "\">link</a>");

And then comment out this next line which would sign the user in before they have used the email above to confirm their account.

//await _signInManager.SignInAsync(user, isPersistent: false);

Next in the Login function add the following bit of code just before the call to _signInManager.PasswordSignInAsync. This looks up the user by email address and returns an error if the account has not been confirmed.

var user = await _userManager.FindByNameAsync(model.Email);
if (user != null)
{
    if (!await _userManager.IsEmailConfirmedAsync(user))
    {
        ModelState.AddModelError(string.Empty, 
                                 "You must have a confirmed email to log in.");
        return View(model);
    }
}

The last change is in the ForgotPassword function. Uncomment the following code to send the user an email to reset their password.

var code = await _userManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = Url.Action("ResetPassword", 
                             "Account", 
                             new { userId = user.Id, code = code }, 
                             protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Reset Password",
 "Please reset your password by clicking here: <a href=\"" + callbackUrl + "\">link</a>");
return View("ForgotPasswordConfirmation");

Forgot Password View

In ForgotPassword.cshtml uncomment the following section to show the UI associated with email based password reset.

<form asp-controller="Account" asp-action="ForgotPassword" method="post" class="form-horizontal" role="form">
    <h4>Enter your email.</h4>
    <hr />
    <div asp-validation-summary="ValidationSummary.All" class="text-danger"></div>
    <div class="form-group">
        <label asp-for="Email" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input asp-for="Email" class="form-control" />
            <span asp-validation-for="Email" class="text-danger"></span>
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <button type="submit" class="btn btn-default">Submit</button>
        </div>
    </div>
</form>

Caution for existing sites

With the changes above if a user has not confirmed their email address then they will not be able to log in or reset their password. Any existing users would need to have their accounts marked as confirmed manually by updating the EmailConfirmed bit field in the AspNetUsers table or be provided away to confirm their account.

Mailgun

Mailgun is an email service that provides a simple API for sending emails and allows up to 10,000 emails to be sent free every month. I have only used mailgun for sending test emails so I can’t speak to how it holds up at scale.

After signing up for an account click on the domains tab and select the only existing active domain which should start with something like sandbox.

Storing Configuration

In my project I created an EmailSettings class that will be loaded from user secrets in the start up of the application. For more details on general configuration in ASP.NET Core check out this post and thenthis post for more details on user secrets. The following is my email settings class.

public class EmailSettings
{
    public string ApiKey { get; set; }
    public string BaseUri { get; set; }
    public string RequestUri { get; set; }
    public string From { get; set; }
}

If using mailgun the above fields map to the following from the mailgun domain page.

EmailSettings Mailgun Example
ApiKey API Key key-*
BaseUri API Base URL https://api.mailgun.net/v3/
RequestUri API Base URL sandbox*.mailgun.org
From Default SMTP Login postmaster@sandbox*.mailgun.org

A couple of notes to the above table on what I actually saved in my config files.

EmailSettings Field Note Example
ApiKey Used with basic auth and needs username api:key-*
RequestUri Needs the API end point to call sandbox*.mailgun.org/messages

The following is what my actual config files ends up looking like.

{
  "EmailSettings": {
    "ApiKey": "api:key-*",
    "BaseUri": "https://api.mailgun.net/v3/",
    "RequestUri": "sandbox*.mailgun.org/messages",
    "From": "postmaster@sandbox*.mailgun.org"
  }
}

In the ConfigureServices function Startup.cs I added a reference to the new settings class so it would be available for dependency injection.

services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));

Message Services

In the Services folder there is a MessageServices.cs file which contains the AuthMessageSender class that has an empty implementation for sending email base on an IEmailSender interface which defines a single SendEmailAsync method. This function is already being called in the code that was uncommented above so I am going to use it to call mailgun’s API.

First I need to get the email settings defined above injected into the AuthMessageSenderClass by adding a class level field and a constructor. The only thing the constructor is doing is saving a reference to the injected settings class.

private readonly EmailSettings _emailSettings;

public AuthMessageSender(IOptions<EmailSettings> emailSettings)
{
    _emailSettings = emailSettings.Value;
}

Next is the SendEmailAsync function mentioned above which I changed to an async function and added the code to send an email using mailgun’s API.

public async Task SendEmailAsync(string email, string subject, string message)
{
    using (var client = new HttpClient { BaseAddress = new Uri(_emailSettings.BaseUri) })
    {
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
            Convert.ToBase64String(Encoding.ASCII.GetBytes(_emailSettings.ApiKey)));

        var content = new FormUrlEncodedContent(new[]
        {
            new KeyValuePair<string, string>("from", _emailSettings.From),
            new KeyValuePair<string, string>("to", email),
            new KeyValuePair<string, string>("subject", subject),
            new KeyValuePair<string, string>("text", message)
        });

        await client.PostAsync(_emailSettings.RequestUri, content).ConfigureAwait(false);
    }
}

This code is using the HttpClient to send a request to mailgun’s API using basic authorization and form url encoded content to pass the API the relevant bit of information.

With that your application will now email account conformations and password resets.

Other Email Options

Mailgun is obviously not the only option for sending emails. This post from Mashape lists 12 API providers. In addition SMTP is also an option which this post by Steve Gordon covers.

Emails using Mailgun in ASP.NET Core Read More »

Configuration in ASP.NET 5

ASP.NET 5 offer a lot of options for loading configuration data such as json files, ini files, XML files, in memory collections, command line arguments, user secrets and environment variables.

The following has at least one example of each type of configuration. Configurations are setup in the constructor of the Startup class.

public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
    // Setup configuration sources.
    var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
        .AddJsonFile("config.json")
        .AddJsonFile($"config.{env.EnvironmentName}.json", optional: true)
        .AddIniFile("config.ini", optional: true)
        .AddInMemoryCollection(new Dictionary<string, string="">
        {
            {
            "AppSettings:TagLine",
            "InMemoryCollection"
            }
        })
        .AddXmlFile("config.xml", optional:true);

    if (env.IsDevelopment())
    {
        builder.AddUserSecrets();
    }
    builder.AddEnvironmentVariables();
    Configuration = builder.Build();
}

As you can see from the example all the different configuration sources can be used together without any issues. A critical thing to keep in mind is if a configuration option is set in multiple places the last configuration source’s value will be used. For example, using the code above, if the title of a site was sent in config.json and config.ini then the value from config.ini would be used.

An example I have seen the ASP.NET team use many times is to use user secrets for API key when in development and then store the keys in environment variables for production.

Here are the relevant lines from the dependencies section of the project.json file.

"Microsoft.Framework.Configuration.Abstractions": "1.0.0-beta7",
"Microsoft.Framework.Configuration.Json": "1.0.0-beta7",
"Microsoft.Framework.Configuration.UserSecrets": "1.0.0-beta7",
"Microsoft.Framework.Configuration.Xml" : "1.0.0-beta7"

Another great feature is being able to load an object with the values from a configuration section. The following is a class created to hold the settings for an application.

public class AppSettings
{
    public string Title { get; set; }
    public string TagLine { get; set; }
}

Then in the ConfigureServices function this is all that is needed to load the class.

services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

Now instead of directly accessing the configuration classes in the HomeController the AppSettings class can be used instead. Here is an example of using ASP.NET 5’s built-in dependency to automatically get a reference to AppSetting via constructor injection.

private readonly IOptions _appSettings;

public HomeController(IOptions appSettings)
{
    _appSettings = appSettings;
}

And then using the _appSettings in the index action to pass values to the view.

public IActionResult Index()
{
    ViewData["Title"] = $"{_appSettings.Options.Title} - " +
                        $"{_appSettings.Options.TagLine}";
    return View();
}

The above is using C# 6’s new interpolated string feature.  The dollar sign before the string is what triggers the feature and allow use variables when wrapped in curly braces.

Check out this github repo for the internals of configuration in ASP.NET 5 .

I also recommend checking out the new Introduction to ASP.NET 5 course on Microsoft Virtual Academy. It covers a lot of good information including live.asp.net which is a production site used to for the ASP.NET 5 community stand up.

Configuration in ASP.NET 5 Read More »

ASP.NET 5 Web Site to Azure

At the point the basics of my ASP.NET 4 contacts application have been moved to the ASP.NET 5. This is never going to be a production application, but I want it run it on a remote server just to prove it works. I decided to publish to Microsoft Azure which is Microsoft’s cloud offering. The process was a lot more challenging that I had expected, but as with all the rough spots I have hit with ASP.NET 5 I am sure the path will be made smooth for the final release.

Publishing to Azure from Visual Studio 2015 RC

To get started right click on the project to be published and select the Publish.

ProjectRightClickPublishMenu

This will load the Publish Web dialog. On the Profile tab select the Microsoft Azure Web Apps option.
PublishDialogProfile

This will show the Select Existing Web App dialog. Click the New button to add a new Web App.
AzureWebAppDialog

The new button show the Create Web App on Microsoft Azure. This dialog has a bit more to it. Web App name sets the url of the app as well as the app name with Azure. For region I just chose the closest data center. My application uses a database and I don’t have an existing database server in Azure so I chose Create new server for Database server selection. Database username and password are self explanatory. With all the options filled in click Create.
AzureCreateWebApp

After the creation process, which creates all the infrastructure need for the app in Azure, is done Visual Studio returns to the Publish Web dialog. The following is the Connection tab. The fields are editable, but are auto filled from the creation process. In case changes are need use the provided Validate Connection button to verify Visual Studio is still able to communicate with Azure.
PublishDialogConnection

The Settings tab allows selection of Release or Debug configurations as well as the target DNX version.
PublishDialogSettings

The last tab on the Publish Web dialog is Preview. It is not overly useful on a first publish since all the file for the project needed to be push, but on subsequent publishes it would be useful to verify nothing unexpected is being pushed.PublishDialogPreview

Pushing the Publish button on the Publish Web dialog push the files to Azure and opens a browser with the newly published web app.

Issues

After a few seconds I was greeted with a HTTP 500 Internal Server Error instead of my web app. I spent a lot of time on the Azure Portal trying to find my issue. I created a new project and published it without issue which means it is a problem with my app and not the publish process. I spent a lot of time digging and Googling my issues, but thankfully ended up with answers.

App Configuration

My first issues were the result of not setting up the configuration options for my user secrets. As I posted last week this was the main worry I had with user secrets. You would think with my concerns that would be the first thing I checked but it actually took me awhile to get around to checking my user secrets. Just to be clear I am not against user secrets I think they are an awesome feature I am just not used to dealing with this side of configuration. The steps to make the proper configuration for user secrets follow.

From the Azure Portal click Browse everything to get a list of all resources.

AzurePortal

From All resources click on the Web App that needs configuration. If you are paying close attention you will notice the name of my web app is different than the publication settings above. This is the result of one of my tries to get the site running before discovering the problem was configuration.
AzurePortalAllResources

Selecting a web app cause the details page to load. On the details page select Settings.
AzurePortalWebAppDetail

From the settings details page click Application Settings which will load the Web app settings page.AzurePortalWebAppSettings

In Web app settings scroll down to the App settings section. In my case I was missing the Authentication:Google:ClientId and Authentication:Google:ClientSecret settings used for OAuth with Google. Also make note of the Connection strings section as  this is the section where the connection string to the database needs to be entered.
AzurePortalWebAppSettingsAuthAndConnection

With all the above changes I was finally able to get the site to load.

Database/Entity Framework

As soon as I click on the contact list section of my app I got another HTTP 500 Internal Server Error. This happens to be the first time the app hits the database. The issue this time is that the DefaultConnection string that needs set so the app can connect to the database.

First step to fix this issue is to go back to the All resources on the Azure Portal and select the database that goes with the web app, aspnetcontacts_db in this example.

AzurePortalAllResourcesDb

This will load the SQL Database detail. Under Connection string is a link for Show database connection strings. Clicking this will load a page with a list of connection strings for this database. Copy the appropriate string and replace the dummy password with the real one. Take that connection string with the password enter and put it in your web app’s DefaultConnection. With the DefaultConnection set the 500 error went away.
AzurePortalDbDetailThe next time I ran I got a stack trace with a message that migrations needed to be run. In order to get migrations to run I made a few changes to my project.

The first change was in the ConfigureServices function of Startup.  I added the setup for the ContactsDbContext using the DefaultConnection string. In the ContactsDbContext I removed the OnConfiguring function which is where the connection string for the ContactsDbContext had been set before.

// Add EF services to the services container.
services.AddEntityFramework()
   .AddSqlServer()
   .AddDbContext<ApplicationDbContext>(options =>
       options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]))
   .AddDbContext<ContactsDbContext>(options =>
       options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

In order to actually run migrations for the ContactsDbContext I added a constructor with a call to Database.AsRelational().ApplyMigrations() which will ensure anytime the DbContext is constructed that the latest migrations will be applied. The following is the full ContactsDbContext class after the changes.

public class ContactsDbContext : DbContext
{
    private static bool _created;
    public DbSet<Contact> Contacts { get; set; }

    public ContactsDbContext()
    {
        if (!_created)
        {
            Database.AsRelational().ApplyMigrations();
            _created = true;
        }
    }
}

The last project change was to the ContactsController to allow ASP.NET to inject the ContactsDbContext instead of creating the context with in the controller.

private readonly ContactsDbContext _db;

public ContactsController(ContactsDbContext dbContext)
{
    _db = dbContext;
}

The change made above to the ConfigureServices function in the Startup class is how ASP.NET knows what to inject into the ContactsController. Build in dependence injection is one of the new features of ASP.NET 5.

After all the above changes I published to Azure and tried to access the contact list again. This resulted in a different error and a stack trace. The issue this round turned out to be that the default SQL Server created by Azure does not support the way that Entity Framework 7 is auto incrementing the ID column on contacts table. Thankfully there is an updated version of SQL available and the default server just need to be upgraded.

Back on the detail page for the SQL database there is a Server version listed as V2. Click the V2.

AzurePortalDbDetail

This will load the Latest SQL database update page. Click Upgrade This Server.

AzurePortalDbUpgrade

Currently the SQL Server created by the Visual Studio 2015 RC is in the Web tier which does not support the latest version of SQL which resulted in the warning below.
AzurePortalDbUpgradePriceWarningClick on your database name to load the Recommended pricing tier page. Since this is a new database Azure does not have enough information to recommend a tier and defaults to S0. At the very bottom of the page there is a big blue S0 link. Click it to change pricing tiers.

AzurePortalDbUpgradePriceRecommended

The Choose your pricing tier page will load. The current setting for the server is Web which shows as a retired. I chose the Basic tier but anything that is not marked as retired should support the newer version of SQL Server. After clicking on the option you want click the Select button at the bottom of the page.

AzurePortalDbUpgradePriceSelect

Now that the new pricing tier has been selected go back to the server details and click the V2 link under Server version. This round you will get a big warning. Under the warning enter the name of your server and click OK to perform the upgrade.

AzurePortalDbUpgradeTypeServerName

The upgrade process took less than 20 minutes for me. After the processes was complete the app worked as expected.

ASP.NET 5 Web Site to Azure Read More »

User Secrets

User secrets are a new concept in ASP.NET 5 which provide a way to use configuration values that are outside of the set of files that would be check into version control. An example of a good use case is the Google client ID and client secret I used in my OAuth post. This is information you would not want in a public repo.

If you are using the ASP.NET 5 Preview Web Site Template then user secrets is already set up and ready to go. If not check out this site which explains all about the user secrets functionality as well as how to use dnu to install the secret manager.

Even with user secrets already set up with the Visual Studio template I am going to point out some of the important bits.

In the project.json file there are a couple of items related to user secrets. The first item is the user secrets ID for the project. The ID seems to be a combination of the project name and some randomly generated text.

"userSecretsId": "Your Secret ID"

The next item in the project.json is in the dependencies section.

"Microsoft.Framework.ConfigurationModel.UserSecrets": "1.0.0-beta4"

The next reference is found in Startup.cs in the constructor where the rest of the configuration is set up.

if (env.IsEnvironment("Development"))
{
    configuration.AddUserSecrets();
}

configuration.AddEnvironmentVariables();

It is important to note that the last configuration added takes priority. Using the above configuration setup with user secrets added first and environment variables added second if both configurations contained a setting for connection string then the one in environment variables would be used. If the connection string did not exist in environment variables then the values from user secrets would be used.

To access user secrets right-click on the project file and select manage user secrets.

ManageUserSecretsMenu

The Manage User Secrets menu choice will open up the secrets.json file. This file will not be located anywhere in the project’s directory structure. The actual file location can be found at “%APPDATA%\Microsoft\UserSecrets\<userSecretsId>\” but you should not really need to know the location or edit the file outside of Visual Studio or user-secret command line tool. Especially while using the beta since the location may not be finalized.

This is my set up of my current secret.json which I am using to store the values needed for OAuth with Google.

{
  "Authentication": {
    "Google": {
      "ClientId": "Your Client Id",
      "ClientSecret": "Your Client Secret"
    }
  }
}

In Statup.cs the ConfigureServices function I was able to replace my hard-coded Client Id and Client Secret with values from my secrets.json.

services.Configure(options =>
{
    options.ClientId = Configuration["Authentication:Google:ClientId"];
    options.ClientSecret = Configuration["Authentication:Google:ClientSecret"];
});

With those changes above sensitive information will be less likely to accidentally get check in to GitHub or any other repo. The only concern I have with setup is a configuration value getting added to a developer’s user secret but that setting never making it into the other develops or production configurations. That worry exists even when checking in configuration to source control just seem more likely to get missed when the values are outside of the project. Even with that concern user secrets are a great features that should help prevent private information from making it out into the public.

User Secrets Read More »