Distributed Mind


Musings on software development

Integration-testing ASP.NET 5 / MVC 6 Controllers on DNX Beta 4 #aspnet5

Written on 16. May 2015

In ASP.NET 5 bootstrapping a self host test server has changed compared to ASP.NET 4 / Web API.

This post will show you how you can run integration tests using ASP.NET 5 / MVC 6 API Controllers on Beta 4 of DNX.

First, the Controller implementation:

CustomersController.cs:

[Route("api/[controller]")]
public class CustomersController
{
    [HttpGet]
    public IActionResult GetAll()
    {
        return new ObjectResult(
            new List<Customer>()
            {
                new Customer
                {
                    CompanyName = "PDMLab",
                    AddressLine = "Ludwig-Erhard-Allee 10",
                    ZipCode = "76131",
                    City = "Karlsruhe",
                    Website = "https://pdmlab.com"
                }
            });
    }
}

Our tests will use Xunit, so we’ll add Xunit to our project.json file:

...
 "dependencies": {
    "Microsoft.AspNet.Mvc": "6.0.0-beta4",
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta4",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta4",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta4",
    "xunit": "2.1.0-*",
    "xunit.runner.dnx": "2.1.0-beta2-build79",
    "xunit.runner.visualstudio": "2.1.0-beta1-build1051"
  },
...

Furthermore, our HttpClient we’re using resides in Microsoft.AspNet.WebApi.Client which we’ll add also to our project.json file:

...
 "dependencies": {
    "Microsoft.AspNet.Mvc": "6.0.0-beta4",
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta4",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta4",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta4",
    "Microsoft.AspNet.WebApi.Client": "5.2.3",
    "xunit": "2.1.0-*",
    "xunit.runner.dnx": "2.1.0-beta2-build79",
    "xunit.runner.visualstudio": "2.1.0-beta1-build1051"
  },
...

Finally, we need Kestrel to run our tests on *nix based systems as well as Microsoft.AspNet.Hosting which contains the classes required for bootstrapping a self host server - :

...
  "dependencies": {
    "Kestrel": "1.0.0-beta4",
    "Microsoft.AspNet.Hosting": "1.0.0-beta4",
    "Microsoft.AspNet.Mvc": "6.0.0-beta4",
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta4",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta4",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta4",
    "Microsoft.AspNet.WebApi.Client": "5.2.3",
    "xunit": "2.1.0-*",
    "xunit.runner.dnx": "2.1.0-beta2-build79",
    "xunit.runner.visualstudio": "2.1.0-beta1-build1051"
  },
...

The final part required is the test itself:

public class CustomerControllerIntegrationTest
    {
        [Fact]
        public void ShouldReturnCustomer()
        {
            var config = new Configuration();
            config.AddCommandLine(new[] { "--server.urls", "http://localhost:5001" });

            var serverFactoryLocation = string.Empty;
            if(!IsMono()) {
                serverFactoryLocation = "Microsoft.AspNet.Server.WebListener";
            } else {
                serverFactoryLocation = "Kestrel";
            }
            var context = new HostingContext()
            {
                Configuration = config,
                ServerFactoryLocation = serverFactoryLocation,
                ApplicationName = "AspNet5IntegrationTesting",
                StartupMethods = new StartupMethods(builder => builder.UseMvc(), services =>
                {
                    services.AddMvc();
                    return services.BuildServiceProvider();
                })
            };


            using (new HostingEngine().Start(context))
            {
                var client = new HttpClient();
                var customers = client.GetAsync("http://localhost:5001/api/customers").Result
                    .Content.ReadAsAsync<List<Customer>>().Result;

                Assert.Equal(customers[0].CompanyName,"PDMLab");
            }
        }

        public static bool IsMono()
        {
            return Type.GetType("Mono.Runtime") != null;
        }

    }

The implementation is pretty straight forward:

First we’re adding the host and port our test server should listen on to our application configuration.

Then we’re checking if we’re running on mono and depdending on the result, we’re bootstrapping Kestrel oder WebListener.

After that we’re bootstrapping a HostingContext instance which configures our StartupMethods (which contains the stuff that resides in your Startup.cs normally), Configuration and the host to use.

Using this context we’re firing up a new HostingEngine instance which gets disposedd after the assertions have finished.

That’s it… almost, because there’s one caveat:

The tests currently fail on Kestrel / *nix with this error:

xUnit.net DNX test runner (64-bit DNX 4.5.1)
Copyright (C) 2015 Outercurve Foundation.

Discovering: AspNet5IntegrationTesting
Discovered:  AspNet5IntegrationTesting
Starting:    AspNet5IntegrationTesting
   AspNet5IntegrationTesting.Tests.CustomerControllerIntegrationTest.ShouldReturnCustomer [FAIL]
      System.ArgumentException : GCHandle value belongs to a different domain
      Stack Trace:
           at System.Runtime.InteropServices.GCHandle.op_Explicit (IntPtr value) [0x00000] in <filename unknown>:0 
           at System.Runtime.InteropServices.GCHandle.FromIntPtr (IntPtr value) [0x00000] in <filename unknown>:0 
           at Microsoft.AspNet.Server.Kestrel.Networking.UvMemory.DestroyMemory (IntPtr memory) [0x00000] in <filename unknown>:0 
           at Microsoft.AspNet.Server.Kestrel.Networking.UvLoopHandle.ReleaseHandle () [0x00000] in <filename unknown>:0 
           at System.Runtime.InteropServices.SafeHandle.RunRelease () [0x00000] in <filename unknown>:0 
           at System.Runtime.InteropServices.SafeHandle.Dispose (Boolean disposing) [0x00000] in <filename unknown>:0 
           at System.Runtime.InteropServices.SafeHandle.Dispose () [0x00000] in <filename unknown>:0 
           at Microsoft.AspNet.Server.Kestrel.KestrelThread.ThreadStart (System.Object parameter) [0x00000] in <filename unknown>:0 
         --- End of stack trace from previous location where exception was thrown ---
           at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x00000] in <filename unknown>:0 
           at Microsoft.AspNet.Server.Kestrel.KestrelThread.Stop (TimeSpan timeout) [0x00000] in <filename unknown>:0 
           at Microsoft.AspNet.Server.Kestrel.KestrelEngine.Dispose () [0x00000] in <filename unknown>:0 
           at Kestrel.ServerFactory+<>c__DisplayClass3_0.<Start>b__1 () [0x00000] in <filename unknown>:0 
           at Microsoft.AspNet.Server.Kestrel.Disposable.Dispose (Boolean disposing) [0x00000] in <filename unknown>:0 
           at Microsoft.AspNet.Server.Kestrel.Disposable.Dispose () [0x00000] in <filename unknown>:0 
           at Microsoft.AspNet.Hosting.HostingEngine+<>c__DisplayClass9_0.<Start>b__1 () [0x00000] in <filename unknown>:0 
           at Microsoft.AspNet.Hosting.HostingEngine+Disposable.Dispose () [0x00000] in <filename unknown>:0 
           at AspNet5IntegrationTesting.Tests.CustomerControllerIntegrationTest.ShouldReturnCustomer () [0x00000] in <filename unknown>:0 
           at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
           at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0 
Finished:    AspNet5IntegrationTesting

=== TEST EXECUTION SUMMARY ===
   AspNet5IntegrationTesting  Total: 1, Errors: 0, Failed: 1, Skipped: 0, Time: 0.697s

If somebody has an idea about this, please send me a pull request at GitHub (yes, you can grab the source over there) ;-)

Update [2015/05/17]: This is a known Kestrel issue as described here (Description starts here) and a fix is on the way.

Deploying a ASP.NET MVC 6 API as Azure API App in Azure App Services

Written on 02. May 2015

Setting some context…

Disclaimer: this post is based on Visual Studio 2015 RC, DNX beta 4 and Azure SDK 2.6 and might become obsolete (hopefully pretty fast).

At Build 2015 “The Lesser Scotts“ have been showing how to create a Azure API App based on ASP.NET Web API 2 using the Azure SDK Tools in Visual Studio 2013 which you should definitely watch before reading this post.

Well, deploying stable stuff is pretty neat.
But my first thought of course has been “What about ASP.NET MVC 6 on DNX beta 4?”.

So I asked the lesser Scotts at Twitter:

Scotts answer was pretty promising:

My next step of course was installing Azure SDK 2.6 for Visual Studio 2015 RC and trying to create a new Azure API App as shown in the video above.

But there were no templates… so back to Twitter - this time Brady Gaster was my victim:

No promising answer but at least some facts :)

Ok, lets do some reverse engineering using Visual Studio 2013 and Azure SDK 2.6 and find out what happens when you’re using the SDK tooling - I’ll skip this step here and show you, how to get stuff done in Visual Studio 2015 RC and ASP.NET MVC 6 on DNX beta 4 now.

First things first, the ASP.NET MVC 6 API

First, create a new ASP.NET Web Application in Visual Studio 2015 RC:

After this, your solution should look like this:

As the default ValuesController.cs in the Controllers folder is pretty useless (and it will cause problems as you can read later on), we’ll delete it and create a SpeakersController.cs instead.

SpeakersController.cs:

using System.Collections.Generic;
using HelloApiApps.Models;
using Microsoft.AspNet.Mvc;

namespace HelloApiApps.Controllers
{
    [Route("api/[controller]")]
    public class SpeakersController
    {
        [HttpGet]
        public IEnumerable<Speaker> GetAll()
        {
            return new List<Speaker>
            {
                new Speaker
                {
                    Id = 1,
                    FirstName = "Scott",
                    LastName = "Hanselman",
                    Twitter = "shanselman"
                },
                new Speaker
                {
                    Id = 2,
                    FirstName = "Scott",
                    LastName = "Hunter",
                    Twitter = "coolcsh"
                },
                new Speaker
                {
                    Id = 3,
                    FirstName = "Damian",
                    LastName = "Edwards",
                    Twitter = "DamianEdwards"
                }
            };
        }
    }
}

We also create a folder Models and create a Speaker.cs in it:

Speaker.cs:

namespace HelloApiApps.Models
{
    public class Speaker
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Twitter { get; set; }
    }
}

At this time, you should be able to test your API locally at http://localhost:someport/api/speakers and you should get the JSON representation of our speaker list.

Creating the Swagger API definition file

According to the Scott’s video we now would create the Swagger file, but Swashbuckle shown in the video doesn’t work with ASP.NET MVC 6 right now.

To the rescue, there’s already a work in progress project on GitHub which is porting Swashbuckle to ASP.NET MVC 6: Ahoy!

We create a local clone of Ahoy and for the sake of keeping this post simple, we add the Swashbuckle.Swagger project inside our API Solution as existing project:

Next, we have to register Swashbuckle / Swagger inside our Startup.cs

Startup.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
using Swashbuckle.Application;
using Swashbuckle.Swagger;

namespace HelloApiApps
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
        }

        // This method gets called by a runtime.
        // Use this method to add services to the container
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            // 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();

            services.AddSwagger(s =>
            {
                s.SwaggerGenerator(c =>
                {
                    c.Schemes = new[] { "http", "https" };
                    c.SingleApiVersion(new Info
                    {
                        Version = "v1",
                        Title = "Swashbuckle Sample API",
                        Description = "A sample API for testing Swashbuckle",
                        TermsOfService = "Some terms ..."
                    });
                });

                s.SchemaGenerator(opt => opt.DescribeAllEnumsAsStrings = true);
            });
        }

        // Configure is called after ConfigureServices is called.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            // 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?}");

            // Add MVC to the request pipeline.
            app.UseMvc(routes =>
            {
                routes.EnableSwagger("swagger/docs/{apiVersion}");
            });
        }
    }
}

The default Swagger URL for Swashbuckle has been (as shown in the video): http://somehost:someport/swagger/docs/v1.

By default, with Ahoy this has changed to http://somehost:someport/swagger/v1/swagger.json whereas in both cases v1 depends on the Version property being set during Swashbuckle registration in Startup.cs inside the ConfigureServices method in the code shown above.

Thus, we have to change the route definition back to the old format as Azure API Apps expect it in that format. You can see that inside the Configure method of the Startup.cs in the code shown above.

Next, we can open up our App in a browser again and browse to http://localhost:someport/swagger/docs/v1 and we should get the JSON representation.

Adding Azure API Apps Metadata

Now we need to add the Metadata for the Azure API Apps manually as we don’t have the tooling support right now…

First, add a JSON file named apiapp.json in the root of the API App project:

Then paste this content into it:

 {
  "$schema": "http://json-schema.org/schemas/2014-11-01/apiapp.json#",
  "id": "HelloApiApps",
  "namespace": "microsoft.com",
  "gateway": "2015-01-14",
  "version": "1.0.0",
  "title": "HelloApiApps",
  "summary": "",
  "author": "",
  "endpoints": null
}

Next, add the following folders and files to your wwwroot folder in the API App solution:

The content of the apiDefinition.swagger.json is the output from http://localhost:someport/swagger/docs/v1. Copy and paste it into the file.

Important Note: Make sure your API Controllers don’t contain ambiguous method names (e.g. “Get” twice), this will cause problems at the moment. Thanks to @Mohit for sorting that out!

The last file required, is the apiappconfig.azureresource.json and it’s content is this:

{
  "$schema": "http://schemas.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "$system": {
      "type": "Object"
    }
  },
  "resources": []
}

<Update [2015/05/02]>: Instead of providing a static snapshot of your Swagger API definition, you can also provide an endpoint where the current swagger definition can be read from. This solves two problems: the route can be the new route template Ahoy introduces and your Swagger definition is always up to date when add new API endpoints (Controllers / Methods).

Just update the apiapp.json and add an fill the endpoint property (please note that I’m use the new default Ahoy route here):

 {
  "$schema": "http://json-schema.org/schemas/2014-11-01/apiapp.json#",
  "id": "HelloApiApps",
  "namespace": "microsoft.com",
  "gateway": "2015-01-14",
  "version": "1.0.0",
  "title": "HelloApiApps",
  "summary": "",
  "author": "",
  "endpoints": {
        "apiDefinition": "/swagger/v1/swagger.json"
    }
}

Kudos go to @pkefal for the hint (By the way: if you want to create API Apps using Node.js you should definitely read his article)

</end of update [2015/05/02]>

Another step, the Azure SDK tooling does, is adding two NuGet packages and we have to do that also. Update your project.json and add Microsoft.Azure.AppService.ApiApps.Service and System.IdentityModel.Tokens.Jwtto it.

{
  "webroot": "wwwroot",
  "version": "1.0.0-*",

  "dependencies": {
    "Microsoft.AspNet.Mvc": "6.0.0-beta4",
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta4",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta4",
    "Microsoft.Azure.AppService.ApiApps.Service": "0.9.40",
    "System.IdentityModel.Tokens.Jwt": "4.0.2.202250711",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta4",
    "Swashbuckle.Swagger": "1.0.0-*"
  },

  "commands": {
    "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"
  },

  "frameworks": {
    "dnx451": { },
    "dnxcore50": { }
  },

  "exclude": [
    "wwwroot",
    "node_modules",
    "bower_components"
  ],
  "publishExclude": [
    "node_modules",
    "bower_components",
    "**.xproj",
    "**.user",
    "**.vspscc"
  ]
}

Publishing the API App

If there were tooling support, you could create a new Azure API App using the tooling. Yet: no tooling, thus we have to use the new Azure Portal.

Login using your credentials and create a new Azure API App.

Disclaimer: Depending on your plan and the settings, this will cost you money!

After a few seconds, you’ll get the success notification inside the Azure Portal and you should have a new tile on the Portal startpage and clicking on it should get you some details:

Now make sure to set the “Access Level” inside the “Settings” / “Application Settings” to “public (anonymous)” and click the “Save” button afterwards:

Back to Visual Studio 2015 RC, we can now publish our Azure API App by right clicking the project and selecting “Publish…”:

The next dialog allows you to select where to publish:

Select “Microsoft Azure Web Apps” and click “Next”.

Now from “Existing Web Apps”, select the API App you just created inside the Azure Portal and click “OK”:

The next dialog sums up the connection details and can be confirmed with “Next”:

During the next step, you can choose your DNX version to be used for the API App - the defaults are ok, click “Next”:

The last step is to hit the “Publish” button:

The publishing process should take only a few seconds:

When it is finished, it should open up your default browser showing you this:

Back to the Azure Portal you should now be able to click on the “API Definition” tile and see the API Operations and be able to download the Swagger using the button above the list of Operations.

That’s it!

lowerCamelCase JSON with ASP.NET MVC 6

Written on 01. May 2015

With ASP.NET MVC 6 the default output for JSON is still UpperCamelCase.

To change that to lowerCamelCase JSON, simply add this to the ConfigureServices method:

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.ConfigureMvc(options =>
    {
        (options.OutputFormatters.First(f => f.Instance is JsonOutputFormatter).Instance as
            JsonOutputFormatter).SerializerSettings.ContractResolver = 
            new CamelCasePropertyNamesContractResolver();
    });
}

That’s it!

Running ASP.NET 5 Beta 4 in Docker with DNX runtime #aspnet5 #docker

Written on 27. April 2015

Update [2015-05-02]

As Microsoft has updated it’s Dockerfile to support DNX (beta 4 as of this Update), the introduction of this post has become obsolete and you can jump directly over here (in this post).

</end of update> [2015-05-02]

Microsoft recently changed the naming for the ASP.NET 5 runtime from “K” to “DNX“. With that, the following K utilities have been renamed:

  • kpm -> dnu
  • kvm -> dnvm
  • k -> dnx

When you’re trying to run DNX with the current ASP.NET 5 Docker image being provided by Microsoft, you’ll fail.

Based on the Dockerfile Microsoft provides here, I created a local Docker image to be able to run ASP.NET 5 Beta 4 with the new DNX runtime.

The Dockerfile for the base ASP.NET 5 image goes here:

Update [2015-05-01]

You don’t have to do the following step, there’s also a working Microsoft Dockerfile, just jump to here (in this post), to read the instructions how to use it.

FROM mono:3.12

# Get build dependencies, download/build/install mono 4.1.0
RUN apt-get update -qq \
    && apt-get install -qqy git autoconf libtool automake build-essential mono-devel gettext unzip \
    && git clone https://github.com/mono/mono.git \
    && cd mono \
    && git reset --hard 53dc56ee39a8e3b013231957aca4671b202c6410 \
    && ./autogen.sh --prefix="/usr/local" \
    && make \
    && make install \
    && cd .. \
    && rm mono -r

# Install aspnet 1.0.0-beta4
ENV DNX_FEED https://www.myget.org/F/aspnetmaster/api/v2
ENV DNX_USER_HOME /opt/dnx

RUN curl -sSL https://raw.githubusercontent.com/aspnet/Home/7d6f78ed7a59594ce7cdb54a026f09cb0cbecb2a/dnvminstall.sh | DNX_BRANCH=master sh
RUN bash -c "source $DNX_USER_HOME/dnvm/dnvm.sh \
    && dnvm install 1.0.0-beta4 -a default \
    && dnvm alias default | xargs -i ln -s $DNX_USER_HOME/runtimes/{} $DNX_USER_HOME/runtimes/default"

# Install libuv for Kestrel from source code (binary is not in wheezy and one in jessie is still too old)
RUN LIBUV_VERSION=1.4.2 \
    && curl -sSL https://github.com/libuv/libuv/archive/v${LIBUV_VERSION}.tar.gz | tar zxfv - -C /usr/local/src \
    && cd /usr/local/src/libuv-$LIBUV_VERSION \
    && sh autogen.sh && ./configure && make && make install \
    && rm -rf /usr/local/src/libuv-$LIBUV_VERSION \
    && ldconfig

# Update NuGet feeds

RUN mkdir -p ~/.config/NuGet/
RUN curl -o ~/.config/NuGet/NuGet.Config -sSL https://gist.githubusercontent.com/AlexZeitler/a3412a4d4eeee60f8ce8/raw/45b0b5312845099cdf5da560829e75949d44d65f/NuGet.config

ENV PATH $PATH:$DNX_USER_HOME/runtimes/default/bin

Now lets build the base image:

sudo docker build -t pdmlab/aspnet:1.0.0 .

Based on that, lets create a Dockerfile for our ASP.NET 5 Beta 4 DNX web application:

FROM pdmlab/aspnet:1.0.0
ADD . /app
WORKDIR /app
RUN ["dnu", "restore"]

EXPOSE 5004
ENTRYPOINT ["dnx", "./src/HelloMvc6", "kestrel"]

Update [2015-05-01]

You can also use this Dockerfile using the Microsoft Beta 4 base Image:

FROM microsoft/aspnet:vs-1.0.0-beta4
ADD . /app
WORKDIR /app
RUN ["dnu", "restore"]

EXPOSE 5004
ENTRYPOINT ["dnx", "./src/HelloMvc6", "kestrel"]

</end of update> [2015-05-01]

Update [2015-05-02]

You can use this Dockerfile using the Microsoft DNX Beta 4 base Image:

FROM microsoft/aspnet:1.0.0-beta4
ADD . /app
WORKDIR /app
RUN ["dnu", "restore"]

EXPOSE 5004
ENTRYPOINT ["dnx", "./src/HelloMvc6", "kestrel"]

</end of update> [2015-05-02]

After that, we need to build or application image:

sudo docker build -t aspnet5beta4dnx

With that done, we can run our container:

sudo docker run -t -d -p 80:5004 aspnet5beta4dnx

If erverything went well, you should be able to browse http://localhost/api/values on your host.

The source for the HelloMvc6 application comes here:

project.json:

{
  "webroot": "wwwroot",
  "version": "1.0.0-*",

  "dependencies": {
    "Kestrel": "1.0.0-beta4",
    "Microsoft.AspNet.Mvc": "6.0.0-beta4",
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta4",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta4",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta4"
  },

  "commands": {
    "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000",
    "kestrel": "Microsoft.AspNet.Hosting --server Kestrel --server.urls http://localhost:5004"
  },

  "frameworks": {
    "dnx451": { },
    "dnxcore50": { }
  },

  "exclude": [
    "wwwroot",
    "node_modules",
    "bower_components"
  ],
  "publishExclude": [
    "node_modules",
    "bower_components",
    "**.xproj",
    "**.user",
    "**.vspscc"
  ]
}

Startup.cs:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;

namespace HelloMvc6
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
        }

        // This method gets called by a runtime.
        // Use this method to add services to the container
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            // 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)
        {
            // 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?}");
        }
    }
}

ValuesController.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;

namespace HelloMvc6.Controllers
{
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        // GET: api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}

Stop complaining or improve yourself

Written on 14. February 2015

Working in the IT sector never has offered more choices than nowadays. You can pick from a wide range of hardware platforms supporting an even broader range of operating systems. On top of it, you can pick from a myriad of development platforms and languages.

On the other hand, more and more people working in the IT sector (I’ll focus on software development mostly in this rant) start complaining about so much things in their daily use with their hardware, OS or their development environment / programming language (yes, I also come through this hollow alley). If you start complaining publicly on twitter or Facebook et al. you can even get retweets and likes if you show some creativity when doing it.

Let’s face the sad truth: it won’t change anything until you start acting.

If you don’t like JavaScript, stop complaining and try ES6. If you still don’t like it: ditch it and try something different. Maybe you should focus on HTML5 and CSS3 only. If you don’t like that either, stop doing web development as a whole. You’re not forced to do web development at all.

If you don’t like WPF (like me), don’t do it, maybe AngularJS might be your frontend framework of choice. But if you’re doing the switch, please don’t start complaining about it again. If you don’t like it’s behavior, try ReactJS or start contributing to AngularJS to improve it.

If you think running JavaScript on the server is plain wrong, simply don’t use Node.js/io.js.

If giving up referential integrity is blasphemy for you, don’t use (most of the) NoSQL databases.

If you don’t like Windows (any longer - like me), try Linux, OS X or build your own operating system. You may find it hard to change things, but it’s up to you to understand and learn things like bash scripting, VIM and all that stuff. If you start experiencing doing better is hard, you might understand why existing things are as they are.

It’s your choice to improve yourself or stick with your habbits. But if you stick with them, please do me a favour and stop complaining about them - they have been your own choice.