Monday 13 July 2015

Asp.Net user secrets

So I've been playing around with Asp.Net 5 beta 5 trying to figure out how to use some of the new configuration stuff.  Especially the user secrets stuff.

The idea of user secrets is that you need to have some settings on you dev machine which you don't want in source control.  Things like passwords etc.

I've found the documentation some what lacking so hopefully this overview will help.

Firstly you need to install the user-secret command. The installation instructions aren't too bad and can be found here DNX-Secret-Configuration.

To add the user secrets

Once I had that installed I added the userSecrestsId to my project.json, but that didn't seem to be picked up.

{
    "webroot": "wwwroot",
    "userSecretsId": "aspnet5-4c570577-d4ba-491c-a56c-3f267e3d5211",
    "version": "1.0.0-*",

I found that I need to add this to the startup.js when I loaded the user secrets.

public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder();
            if (env.IsDevelopment())
            {
                builder.AddUserSecrets("aspnet5-4c570577-d4ba-491c-a56c-3f267e3d5211");
            }
            else
            {
                builder.AddEnvironmentVariables();
            }
            Configuration = builder.Build();
        }

The next problem was figuring out how to inject these values into the controller.  What I found is you need to AddOptions in the ConfigureServices method and they Configure the class you want the values put in.

public void ConfigureServices(IServiceCollection services)
       {
           services.AddMvc();
           services.AddOptions();
           services.Configure<AwsOptions>(Configuration);

My AwsOptions class just has two string fields with the name of the secret properties I want to use.

namespace Config
{
    public class AwsOptions
    {
        public string awsAccessKey { getset; }
        public string awsSecret { getset; }        
    }
}

The ASP.NET configuration system will look for values in the Configuration object that match these name and load them into that class.  Then to get them in the controller you do the following


[Route("api/[controller]")]
public class AController : Controller
{
    private readonly IOptions<AwsOptions> _awsOptions;
    private readonly ILogger<SeverController> _logger;
 
    public AController(IOptions<AwsOptions> awsOptions, ILogger<AController> logger)
    {
        _awsOptions = awsOptions;
        _logger = logger;
    }
 
    // POST api/values
    [HttpPost]
    public async Task<IActionResult> Post(Guid Id)
    {

        AmazonSimpleNotificationServiceClient snsclient =  
            new AmazonSimpleNotificationServiceClient(_awsOptions.Options.awsAccessKey,
                 _awsOptions.Options.awsSecret, RegionEndpoint.USWest2);

That's it.  Then you will get your user secret values injected into you class.

Full Startup.cs (because I hate it when the snippets miss something I need)

using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.Framework.Configuration;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Severing.Service.Config;
 
namespace Service
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder();
            if (env.IsDevelopment())
            {
                builder.AddUserSecrets("aspnet5-4c570577-d4ba-491c-a56c-3f267e3d5211");
            }
            else
            {
                builder.AddEnvironmentVariables();
            }
            Configuration = builder.Build();
        }
 
        public IConfiguration Configuration { getset; }
 
        // This method gets called by a runtime.
        // Use this method to add services to the container
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddOptions();
            services.Configure<AwsOptions>(Configuration);
            services.AddLogging();
            // Uncomment the following line to add Web API services which makes it easier to port Web API 2 controllers.
            // You will also need to add the Microsoft.AspNet.Mvc.WebApiCompatShim package to the 'dependencies' section of project.json.
            // services.AddWebApiConventions();
        }
 
        // Configure is called after ConfigureServices is called.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
 
            loggerFactory.AddConsole();
            // Configure the HTTP request pipeline.
            app.UseStaticFiles();
 
            // Add MVC to the request pipeline.
            app.UseMvc();
            // Add the following route for porting Web API 2 controllers.
            // routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
        }
    }
}

Saturday 4 May 2013

Fix for NServiceBus testing.

Looks like the issue I had with NSB testing may not have been the Unobtrusive messages.

What I’ve ended up having to do is this.

   1:  MessageConventionExtensions.IsMessageTypeAction =
   2:                  t => t.Namespace != null && t.Namespace.EndsWith("Messages") && !t.Namespace.StartsWith("NServiceBus");
   3:  Test.Initialize();

Making ConfigurationElementCollection strongly typed.

I was getting annoyed with ConfigurationElementCollection returning IEnumerable and not IEnumerable<T>, after some Googling I came across this post on StackOverflow http://stackoverflow.com/questions/7991252/read-web-config-section-to-list.

Basically you implement IEnumerable<T> and in GetEnumerator do this

   1:   public new IEnumerator<T> GetEnumerator()
   2:   {
   3:      return this.OfType<T>().GetEnumerator();
   4:   }



No more casting when you want to use Linq on the ConfigurationElementCollection Thumbs up

Friday 5 April 2013

Object reference during NServiceBus start up.

One of our NServiceBus services started getting this error today.

Fatal    System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Object.GetType()
   at NServiceBus.Timeout.Core.TimeoutRunner.CacheExistingTimeouts()
   at NServiceBus.Timeout.Core.TimeoutRunner.Run()
   at System.Collections.Generic.List`1.ForEach(Action`1 action)
   at NServiceBus.Unicast.UnicastBus.NServiceBus.IStartableBus.Start(Action startupAction)
   at NServiceBus.Hosting.GenericHost.Start() in c:\TeamCity\buildAgent\work\nsb.master_8\src\hosting\NServiceBus.Hosting\GenericHost.cs:line 34

Turns out the NServiceBus.Persistence connection string was pointing to a Raven instance that was turned off.

Friday 29 March 2013

NServiceBus Testing with Unobtrusive messages

I’ve just had a problem when using nServiceBus.Testing.

When I was running my unit test i was getting
image

Turns out this service was using unobtrusive messages and it appears that nServiceBus.Testing isn’t aware of that and there doesn’t seem to be a way to make it aware.  Currently I’ve just added IMessage to my messages.

NServiceBus config errors

If you get an error about logging when starting a nservice bus service drill down on the exception to see what the real error is.