ServiceWire and .NET Core Integration Tests

I’m very happy with the quick and dirty .NET Core integration test code I’ve just committed to GitHub for ServiceWire. The only changes to existing integration test code were these:

Removal of Named Pipes from the test since .NET Core does not support Named Pipes (so far as I can learn) as Named Pipes is a Windows only thing (again, so far as I have learned).

Modified code to get IP address and port from command line args rather than configuration along with some defaults.

So here’s the primary host host code. Note how easy it is to host implementations for multiple interfaces.

class Program
{
   static void Main(string[] args)
   {
      var logger = new Logger(logLevel: LogLevel.Debug);
      var stats = new Stats();

      var addr = new[] { "127.0.0.1", "8098" }; //defaults
      if (null != args && args.Length > 0)
      {
         var parts = args[0].Split(':');
         if (parts.Length > 1) addr[1] = parts[1];
         addr[0] = parts[0];
      }

      var ip = addr[0];
      var port = Convert.ToInt32(addr[1]);
      var ipEndpoint = new IPEndPoint(IPAddress.Any, port);

      var useCompression = false;
      var compressionThreshold = 131072; //128KB

      var tester = new NetTester();
      var mytester = new MyTester();

      var tcphost = new TcpHost(ipEndpoint, logger, stats);
      tcphost.UseCompression = useCompression;
      tcphost.CompressionThreshold = compressionThreshold;
      tcphost.AddService<INetTester>(tester);
      tcphost.AddService<IMyTester>(mytester);

      var valTypes = new ValTypes();
      tcphost.AddService<IValTypes>(valTypes);

      tcphost.Open();

      Console.WriteLine("Press Enter to stop the dual host test.");
      Console.ReadLine();

      tcphost.Close();

      Console.WriteLine("Press Enter to quit.");
      Console.ReadLine();
   }
}

And here’s the client code.

class Program
{
   private static void Main(string[] args)
   {
      var addr = new[] { "127.0.0.1", "8098" }; //defaults
      if (null != args && args.Length > 0)
      {
         var parts = args[0].Split(':');
         if (parts.Length > 1) addr[1] = parts[1];
         addr[0] = parts[0];
      }

      var ip = addr[0];
      var port = Convert.ToInt32(addr[1]);
      var ipEndpoint = new IPEndPoint(IPAddress.Parse(ip), port);
      for (int i = 0; i < 1; i++) RunTest(ipEndpoint, ip);

      Console.ReadLine();
   }

   private static void RunTest(IPEndPoint ipEndpoint, string ip)
   {
      using (var client = new TcpClient<IValTypes>(ipEndpoint))
      {
         decimal abc = client.Proxy.GetDecimal(4.5m);
         bool result = client.Proxy.OutDecimal(abc);
      }

      using (var client = new NetTcpTesterProxy(ipEndpoint))
      {
         var id = client.GetId("test1", 3.314, 42, DateTime.Now);
         long q = 3;
         var response = client.Get(id, "mirror", 4.123, out q);
         var list = client.GetItems(id);
      }
      using (var client = new NetTcpMyTesterProxy(ipEndpoint))
      {
         var id = client.GetId("test1", 3.314, 42);
         int q2 = 4;
         var response = client.Get(id, "mirror", 4.123, out q2);
         var list = client.GetItems(id, new int[] { 3, 6, 9 });
      }

      var sw = Stopwatch.StartNew();
      var from = 0;
      var to = 400;
      Parallel.For(from, to, index =>
      {
         using (var client = new NetTcpTesterProxy(ipEndpoint))
         {
            for (int i = 0; i < 10; i++)
            {
               var id = client.GetId("test1", 3.314, 42, DateTime.Now);
               long q = 2;
               var response = client.Get(id, "mirror", 4.123, out q);
               var list = client.GetItems(id);
            }
         }

         using (var client = new NetTcpMyTesterProxy(ipEndpoint))
         {
            for (int i = 0; i < 10; i++)
            {
               var id = client.GetId("test1", 3.314, 42);
               int q2 = 6;
               var response = client.Get(id, "mirror", 4.123, out q2);
               var list = client.GetItems(id, new int[] { 3, 6, 9 });
            }
         }
      });
      sw.Stop();
      var msperop = sw.ElapsedMilliseconds / 24000.0;
      Console.WriteLine("tcp: {0}, {1}", sw.ElapsedMilliseconds, msperop);
   }
}

It’s quite simple, but I’m going to be working on both host and client code to make it easier to code up both of them with some convention assumptions that will also not break existing host and client code. After that, I’ll publish a new NuGet package with a major version rev to 5.0.

ServiceWire on .NET Core

With a few days of free time on my hands, I’ve picked up an old open source project of mine and kicked off a .NET Core port of ServiceWire which still needs testing and much more refactoring, I'm sure. Just getting everything to build was a challenge. Especially in the area of Reflection. Here’s the bridge code I wrote to avoid making to many IFDEF blocks in the code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading.Tasks;

namespace ServiceWire
{
   public static class TypeExtensions
   {
      public static Type BaseType(this Type t)
      {
#if NETSTANDARD1_6
         return t.GetTypeInfo().BaseType;
#else
         return t.BaseType;
#endif
      }

      public static bool IsInterface(this Type t)
      {
#if NETSTANDARD1_6
         return t.GetTypeInfo().IsInterface;
#else
         return t.IsInterface;
#endif
      }

#if NETSTANDARD1_6
      public static MethodInfo[] GetMethods(this Type t)
      {
         return t.GetTypeInfo().GetMethods();
      }
#endif

#if NETSTANDARD1_6
      public static Type[] GetInterfaces(this Type t)
      {
         return t.GetTypeInfo().GetInterfaces();
      }
#endif

#if NETSTANDARD1_6
      public static Type CreateType(this TypeBuilder b)
      {
         return b.CreateTypeInfo().AsType();
      }
#endif

#if NETSTANDARD1_6
      public static ConstructorInfo GetConstructor(this Type t, Type[] ctorArgTypes)
      {
         return t.GetTypeInfo().GetConstructor(ctorArgTypes);
      }
#endif

#if NETSTANDARD1_6
      public static MethodInfo GetMethod(this Type t, string invokeMethod, BindingFlags flags)
      {
         return t.GetTypeInfo().GetMethod(invokeMethod, flags);
      }

      public static MethodInfo[] GetMethods(this Type t, BindingFlags flags)
      {
         return t.GetTypeInfo().GetMethods(flags);
      }

      public static PropertyInfo[] GetProperties(this Type t, BindingFlags flags)
      {
         return t.GetTypeInfo().GetProperties(flags);
      }

#endif

      public static bool IsValueType(this Type t)
      {
#if NETSTANDARD1_6
         return t.GetTypeInfo().IsValueType;
#else
         return t.IsValueType;
#endif
      }

      public static Type[] GetGenericArguments(this PropertyInfo pi)
      {
#if NETSTANDARD1_6
         return pi.PropertyType.GetTypeInfo().GetGenericArguments();
#else
         return pi.PropertyType.GetGenericArguments();
#endif
      }

      public static bool IsGenericType(this Type t)
      {
#if NETSTANDARD1_6
         return t.GetTypeInfo().IsGenericType;
#else
         return t.IsGenericType;
#endif
      }

      public static bool IsPrimitive(this Type t)
      {
#if NETSTANDARD1_6
         return t.GetTypeInfo().IsPrimitive;
#else
         return t.IsPrimitive;
#endif
      }

   }
}

It’s a quick and dirty implementation that needs more work. The split of Type into Type and TypeInfo classes in .NET Core is a pain but I can see why they would want to eliminate Reflection except where it is absolutely necessary.

Token Authentication with ASP.NET Core

I’ve spent a lot of time over the last 16 months or so working with ASP.NET Web API and Microsoft.Owin’s UseOAuthAuthorizationServer middleware extending it with custom OAuthAuthorizationServerOptions, ISecureDataFormat<T>, OAuthAuthorizationServerProvider and IAuthenticationTokenProvider implementations.

This included the use of the System.IdentityModel.Tokens InMemorySymmetricSecurityKey used in the SigningCredentials constructor to be used in signing the JWT token. And when I went to port all of this to ASP.NET Core, I learned to my surprise that there is no equivalent to UseOAuthAuthorizationServer middleware and there is no InMemorySymmetricSecurityKey. Instead, you’re on your own for creating your own authentication/authorization middleware and signing a JWT is done using a SymmetricSecurityKey (a class that used to be abstract but now is not).

Here’s my first attempt:

salt = salt ?? "0a987sdf7asdg896asdf6as9df7a7sdf8asd";
var keyBytes = Encoding.UTF8.GetBytes(
    Convert.ToBase64String(Encoding.UTF8.GetBytes(SecKey + salt)));
_symmetricSecurityKey = new SymmetricSecurityKey(keyBytes);
_tokenValidationParameters = new TokenValidationParameters
{
    CryptoProviderFactory = _symmetricSecurityKey.CryptoProviderFactory,
    ValidateIssuerSigningKey = false, //true,
    IssuerSigningKey = _symmetricSecurityKey,
    ValidateIssuer = true,
    ValidIssuer = "issuername",
    ValidateAudience = true,
    ValidAudience = "all",
    ValidateLifetime = true,
    ClockSkew = TimeSpan.Zero
};
_signingCredentials = new SigningCredentials(_symmetricSecurityKey, "HS256");

A very good blog post on this topic can be found on Stormpath’s blog. I highly recommend you read that blog post. There are any number of ways to code up your “token” endpoint. I like how easy it is to write a custom authentication and authorization token endpoint using ASP.NET Core. More fun with .NET Core to follow.

Microsoft REST API Guidelines

I’m a big believer in establishing standards for your REST APIs. I like this one from Microsoft but there are others. What I like about this particular guideline is the structural organization and its brevity. The introductory paragraph provides the reasoning and justification behind REST even when there are language specific SDKs made available.

Developers access most Microsoft Cloud Platform resources via RESTful HTTP interfaces. Although each service typically provides language-specific frameworks to wrap their APIs, all of their operations eventually boil down to REST operations over HTTP. Microsoft must support a wide range of clients and services and cannot rely on rich frameworks being available for every development environment. Thus a goal of these guidelines is to ensure Microsoft REST APIs can be easily and consistently consumed by any client with basic HTTP support.

One thing that would be nice to have is a standard for filtering, paging, etc., on the URL as query parameters. These get defined differently by every REST service architect out there. Or so it seems. A good jumping off point for some research and thought.

And I want to thank my friend Pablo for sending me the link to this.

Upgrade to Visual Studio 2015 Update 3 and .NET Core Tooling

Yesterday I installed the Visual Studio 2015 Update 3 and began playing with a new ASP.NET Core API project. But the NuGet packages needed to be updated and when I tried to update them, they could not be found.

Clue: Pay attention to the little black flag in the upper right corner of Visual Studio 2015 (flag) and install the .NET Core 1.0.0. VS 2015 Tooling Preview 2.

tooling

The install took a fair amount of time, but when it was done, I created a new ASP.NET Core API project and bada-bing, everything seems happy.

MSBuild and Web Deployment Just Stops

This super helpful error message and some Googling led to a solution. I really did not believe it when I found it. But some days are like that.

Severity    Code    Description    Project    File    Line    Suppression State
Error        Web deployment task failed. ((6/29/2016 10:07:24 AM) An error occurred when the request was processed on the remote computer.) (6/29/2016 10:07:24 AM) An error occurred when the request was processed on the remote computer. Unable to perform the operation. Please contact your server administrator to check authorization and delegation settings.

And the winning blog post (certainly not MS docs) goes to A Software Guy’s Blog (Eric Kelm).

Summary
When you add Microsoft Web Deploy to an IIS server, the install adds two local user accounts, both with an expiring password. So 90 days, or whatever your expiration policy is, after you install, web deployment just stops working. The trick is to modify both accounts to check “password never expires”.

Thanks, Eric. And thanks, Microsoft. Eric’s post is four years old and this problem still exists. Epic fail.

Upgrading to .NET Core RTM and CamelCasing

This post is primarily a place holder and reminder to review Rick Strahl’s post on this topic a few more times.

The change in default serialization does not yet affect me because I was not relying on RC2 for anything serious. However it is critical to note this default behavior for future reference because many of my APIs serialize “as is” so most of my JSON is PascalCase and changing that midstream would bork every client that relies on case sensitivity in the data.

I particularly like Rick’s take on this:

“Personally I prefer to see stuff like this as an easily accessible option, and not something that is rammed down your throat - serialization shouldn't arbitrarily change the naming of properties. While that is often desirable I'm betting there are plenty of scenarios (especially when dealing with .NET to .NET) where you'd much rather have the serialized content reflect the original naming.

“It's especially frustrating in that this doesn't just affect server code where you could easily refactor, but client side code that may already be running. It also makes it harder to port existing code to ASP.NET core and it's not exactly something that's super easy to find if you're searching unless you already know that there serializer settings being sent to JSON.NET somewhere in the framework.”

Well, now the real play begins with .NET Core 1.0 RTM.