Thursday, February 1, 2018

AWS: Connect to Elasticache-Redis instance from Lambda Function using C#

Synopsis
Connecting a Lambda to Elasticache/Redis is not your typical use case.   Elasticache was initially built to be used by EC2 instances.  In 2016 / 2017 AWS added the ability to connect to Elasticache via VPCs and thus a way in with your Lambdas, because Lambdas can also run in VPCs.  Run both the Lambda and the Elasticache instance in the same VPC with the right security groups and you’ll be able to connect to an Elasticache/Redis instance from a Lambda.

Below is a walkthrough of how to set up this connectivity with some sample code.


Walkthrough - Creating a VPC to run your Lambda and Elasticache in:

Please understand this is my freshman level setup of a VPC to allow for connecting a Lambda to an Elasticache-Redis instance.  It gets the job done but should be tightened down from a security standpoint (not in this document).

From a high level you’ll need to:

1. Create the VPC
2. Create the VPCs Subnets
3. Create a Route table for the VPC
4. Create the Security group for the VPC
5. (optionally) Create Endpoints to different AWS services if needed
6. (optionally) Replace the auto created Network ACL with a properly named version

Here are the steps:

  1. Navigate to the VPC Dashboard in the AWS Console
  2. Choose the Create button to create a new VPC instance:
    1. Choose “Yes, Create” to create the VPC 
    2. The above CIDR block is “private” and can be used in your environment per: 
      1. https://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Subnets.html
      2. http://www.faqs.org/rfcs/rfc1918.html 
    3. You could use the 10.* or 172.16.* block spaces as well.   Other than those ranges I am a noob in the VPC space.
  3. Create at least two subnets:
    1. Names are important.  Probably a good idea to include the name of the Availability Zone in the name tag along with the VPC name for easy reference later.
    2. Choose the VPC created.
    3. Give it a unique CIDR block
    4. For example, I created AppV3_east1a and AppV3_east1b with CIDR blocks of 192.168.0.0/25 and 192.168.1.0/26 against us-east-1a and us-east-1b.
  4. Create a Route Table:
    1. After choosing Yes, Create, configure the route table as follows (add our two subnets to it):
    2.  
  5. Create a VPC security group which our Lambda will use:
    1. Adjust Inbound Rules, then save.  Use 0.0.0.0/0 to get past this:
      1. Note: May be a good idea to lock this down further but that is beyond the scope of this document.
  6. Optionally:
    1. The VPC will automatically create a Network ACL for your VPC with the subnets you’ve defined.  I added one anyways, named it AppV4_NACL, and assigned the new one the endpoints from the auto created one and gave it the same inbound/outbound rules. 
Walkthrough:  Create Elasticache Instance
  1. Navigate to the Elasticache Dashboard in the AWS Console
  2. (optional) Setup your Elasticache Subnet Group ahead of time
    1. From the Dashboard select Subnet Groups
    2. Choose the Create button and enter the following:
    3.  
    4. Choose “Create” to save the Subnet Group.
      1. Note: The “Name” field only likes hyphens for special characters. On save it will “lower case” all your text.
  3. Navigate to the Redis section, then choose the Create button to create a new Elasticache-Redis instance
  4. Enter the following info:
    1. Note 1: For sample and cost sake choose a small node type of cache.t2.micro
    2. Note 2: For sample sake use “None”
    3.  
  5. Choose a Subnet group (this is the VPC that you’ll run your Lambda and Elasticache Instance from):
    1. If you’ve already got a VPC setup then try using that first, else if you have none then you’ll need to create one which is beyond the scope of this document. (just learned about VPCs, so go to the first Walkthrough for details on VPC setup)
      1. i. The trick is to run both the Lambda and Elasticache/Redis instance in this VPC.
    2. You can choose the group defined above in Elasticache Subnet Group instructions above or perform the Elasticache Subnet Group setup here.
    3.  
  6. Setup your security so that it has enough access:
    1. Note 1: I chose a security group defined by organization called “Allow All”.  For testing purposes I start wide open then dial it back after it is working.
    2. Note 2: If you’ve got a new AWS account then you’ll probably only have the default account to begin with.  Try that to see if that works.  Else follow the VPC setup instructions at the beginning of this document.
    3.  
  7. Leave all other options as default and choose Create to create the instance. 

Walkthrough: Create Lambda
This section assumes you are able to publish your Lambdas to the AWS environment from within Visual Studio.
  1. Create a new Lambda Project
  2. Add the “StackExchange.Redis” NuGet package so you can connect to the Elasticache/Redis instance from you’re Lambda.  :  
    1. Note 1: The AWSSDK.Elasticache Nuget package is meant to manage the infrastructure (Parameter Groups, Subnets, Clusters, etc) of Elasticache and does not assist with actually working with Redis SortedSets, Hashes, Strings, etc.  To do that you have to use a third party NuGet package as I am not aware of any AWS sponsored packages that do this at this time.  For this example, I chose “StackExchange.Redis”.  For a list of others go to: https://redis.io/clients#c. AWS may have one for Memcached though but that is out of scope for this document.  I want to use the SortedSet functionality, so the focus of this document is Redis.
    2. Note 2: Do not choose a StackExchange.Redis higher than 1.2.1 for .Net Core 1.0 deployments.  Versions greater than 1.2.1 are not supported in AWS Lambdas using .Net Core 1.0. Version 1.2.3 attempts to load .netcore 1.1.  AWS recently added support for .Net Framework 2.0, so Version 1.2.6 may be a good choice for that but I have not explored that option yet:
    3.  
    4. For example when I choose 1.2.3 and choose Update we get the following “Review Changes” screen:
      1.  
      2. I chose Cancel at this screen because I want to remain on the AWS SDK for .Net Lambdas which is 1.0.2.
  3. 3. Use this code to get started in your Lambda (yeah this is ugly):
    1. 
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Threading.Tasks;
      
      using Amazon.Lambda.Core;
      using StackExchange.Redis;
      using System.Net;
      
      // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
      [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
      
      namespace TestElasticacheRedis
      {
          public class RedisTest
          {
              private ConnectionMultiplexer _elasticacheConnection = null;
      
              public void FunctionHandler(ILambdaContext context)
              {
                  System.Text.StringBuilder sb = new System.Text.StringBuilder();
      
                  Console.WriteLine("Starting...");
                  if (_elasticacheConnection == null)
                  {
                      _elasticacheConnection = GetConnection();
                  }
                  Console.WriteLine("After Connection");
      
                  var db = _elasticacheConnection.GetDatabase();
                  Console.Write("After GetDatabase, ");
                  Console.WriteLine("isConnected:" + db.IsConnected("timeSorted") + ", dbinstance: " + db.Database);
                  
                  TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
                  var score = t.TotalMilliseconds;
                  
                  //Add to 'timeSorted', store a value of System.Guid, and sort by t.TotalMilliseconds.  
                  //  Search by t.TotalMilliseconds for fast lookup.
                  db.SortedSetAdd("timeSorted", System.Guid.NewGuid().ToString(), score);
      
                  var byScan = db.SortedSetScan("timeSorted");
                  Console.WriteLine("Scan: " + string.Join(",\n", byScan));
      
                  var byRank = db.SortedSetRangeByRank("timeSorted");
                  Console.WriteLine("Rank: " + string.Join(",\n", byRank));
      
                  var byScore = db.SortedSetRangeByScore("timeSorted", score, 1, Exclude.None, Order.Ascending);
                  Console.WriteLine("Score: " + string.Join(",\n", byScore));
      
                  Console.WriteLine("After sortedsetadd");
              }
      
              private ConnectionMultiplexer GetConnection()
              {
                  //because of https://github.com/dotnet/corefx/issues/8768
                  var addresses = Dns.GetHostAddressesAsync(Environment.GetEnvironmentVariable("ElasticacheConnectionString")).Result;
                  var ip4Adresses = addresses.Select(x => x.MapToIPv4()).Distinct().ToList();
                  var config = new ConfigurationOptions
                  {
                      AllowAdmin = true,
                      AbortOnConnectFail = false,
                  };
                  ip4Adresses.ForEach(ip => config.EndPoints.Add(ip, 6379));
                  
                  return ConnectionMultiplexer.Connect(config);
              }
          }
      }
      
      
    2. Note: Be sure to plug in the port of 6379 and the address of your Elasticache in the Environment Variables for the Lambda.  You can find the address here:
    3.  
  4. Setup your IAM role to give your Lambda the ability to execute in AWS and to deploy to AWS:
    1. Setup a role with permissions similar to the below illustration.
      1.  
      2. In order to deploy from Visual Studio to AWS, you’ll need the “ec2:CreateNetworkInterface” Action which the AWSLambdaVPCAccessExecutionRole will give you.
      3. Feel free to cut this down and build your own policy based on what you need vs what you see above.
  5. 5. Deploy your Lambda to AWS:
    1. Choose Next
      1. Populate the two VPC Subnets
      2. Choose the appropriate Security Group
      3. Enter the ElasticacheConnectionString as a Variable.
      4. Choose an IAM role with the following permissions:
        1.  
        2. In order to deploy from Visual Studio to AWS, you’ll need the “ec2:CreateNetworkInterface” Action which the AWSLambdaVPCAccessExecutionRole will give you.
        3. At some point, cut this down and build your own policy based on what you need vs what you see above.
    2. Choose Upload to push the Lambda to your environment.

Troubleshooting:
  1. If you get a  “No connection is available to service this operation”…“UnableToConnect” error, first verify that the IP address that is trying to connect to is in the VPC IP Address range you entered.  If it isn’t then your Lambda is either:
    1. Not pointing to the correct Elasticache-Redis instance url
    2. The Elasticache-Redis instance is not running on the selected VPC
    3. The Lambda is not running on the selected VPC.
      1. Remember, both your Elasticache-Redis and Lambda components need to be setup to run in the same VPC.
  2. If you get a “No connection is available to service this operation”…”It was not possible to connect to the redis server(s)”, try the above then the below:
    1. I think both are running on the same VPC but we’re missing something.
    2. Navigate to the Elasticache Dashboard, then modify the Redis instance, verify the VPC Security Group selected is the “Allow All” we specified earlier.:
      1.  
      2. If not, select the Allow All item and choose the Modify button to save the changes.
      3. Retest the Lambda.
      4. Still no go then in the AWS Console: (The Lambda seems to maintain some state with the VPCs selected):
        1. remove the regions in the lambda, 
        2. save the lambda
        3. Add the regions under VPC back again
        4. Save the lambda
        5. Test the lambda again

Thursday, September 15, 2016

For the love of Jiggling Visual Studio 2015 Update 3 .NetCore Solutions

I've had an opportunity to work with VS.Net 2015 Update 3 for a while now using .Net Core. There are two different flavors of .Net Core projects. I call them:
  1. Core Core: Which is all Core
  2. Core Framework: Which uses .Net Framework 4.61

We've been using Core Framework and it occasionally needs to be (affectionately named) 'jiggled'. Our solutions have more than one project in them and they occasionally barf when trying to communicate to other projects in the solution. These projects may also lose their ability to use dependencies defined in the project.json.

Here are the jiggling tricks that work for our group:
  1. Identify the project or projects that are having issues with their dependencies.
  2. On that project determine if it is trying to reference another project in your solution that is having issues. If so go to that project see if that is having issues. Lather, rinse, repeat.
  3. Now you are in a project with no dependencies on other projects in your solution and it has an issue with it's references.
  4. Jiggle 1: Right-click on references and choose "Restore Package...". If it is fixed, great, if not goto Jiggle 2.
  5. Jiggle 2: Right-click on your project and choose "Unload Project". Then right-click again and choose "Load Project". Repeat Jiggle 1.
  6. Jiggle 3: Right-click on your project and choose "Unload Project". Then from Windows Explorer, not IE, go to your project folder and delete "project.json.lock". Right-click on your project and choose "Load Project" which will rebuild your "project.json.lock". Repeat Jiggle 1.
  7. Jiggle of last Resort: If Jiggle 1 thru 3 don't work and you can't expand your reference tree, then reinstall your Update 3 and the .Net Core SDK then reboot and follow Jiggle 1 thru 3 again. If these don't work then reboot your machine three times and stand on your left foot then commence crying as that is beyond the scope of this little ditty.
Repeat the Jiggle steps for each project in your solution.

Enjoy!

Tuesday, July 5, 2016

Visual Studio 2015 Update 3 with DotNetCore 1.0.0 SDK install with Entity Framework 7 ( EF7 )

Had some fun today trying to get EF7 to work with dotnet core, but finally got through all the issues I was running into. Let me take you on that journey:

In order to proceed you've got to install the following three items (perhaps just the first two...):
1. Visual Studio 2015 Update 3
2. .NET Core for Visual Studio
3. or choose the installer from https://www.microsoft.com/net/download which I perhaps shouldn't have done.

Links for the above can be found in this article which I also use in my explanations below:
https://docs.efproject.net/en/latest/platforms/aspnetcore/existing-db.html

I installed 1 above, then 2, but was still getting an error. In particular I couldn't get this line to run from this tutorial.
 Install-Package Microsoft.EntityFrameworkCore.Tools –Pre  


To troubleshoot I installed the x86 versions of .NET Core SDK Installer (Preview 2) and .NET Core Installer (v1.0) as well to see if that would help. It did until I rebooted after which no references were being displayed. I quickly reinstalled the .Net Core SDK Installer (Preview 2) x64 versions again and that seemed to do the trick.

All three of the install package commands were now installed without restore failures!:
 Install-Package Microsoft.EntityFrameworkCore.SqlServer  
 Install-Package Microsoft.EntityFrameworkCore.Tools –Pre  
 Install-Package Microsoft.EntityFrameworkCore.SqlServer.Design  


Next I tried to get EF7 to work with a raw .Net Core project following the efproject.net link's instructions which needed a little changing.

First change the project.json to the following:
 {  
  "version": "1.0.0-*",  
  "buildOptions": {  
   "emitEntryPoint": true  
  },  
  "dependencies": {  
   "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",  
   "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.0",  
   "Microsoft.EntityFrameworkCore.Tools": {  
    "type": "build",  
    "version": "1.0.0-preview2-final"  
   },  
   "Microsoft.NETCore.App": {  
    "type": "platform",  
    "version": "1.0.0"  
   },  
   "Microsoft.EntityFrameworkCore.Design": {  
    "type": "build",  
    "version": "1.0.0-preview2-final"  
   }  
  },  
  "tools": {  
   "Microsoft.EntityFrameworkCore.Tools": {  
    "version": "1.0.0-preview2-final"  
   },  
   "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",  
   "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"  
  },  
  "frameworks": {  
   "netcoreapp1.0": {}  
  }  
 }   


Key point 1: Can't use EF7 against a class library so we added the buildOptions and emitEntryPoint portion per this article. EF7 won't work against a project that is not an application of some sort (i.e. it can't be a class library). Otherwise you'll see these kinds of errors when you try and run Scaffold-DbContext:
 PM> Scaffold-DbContext "Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer  
 Could not invoke this command on the startup project 'Core.Datav2'. This preview of Entity Framework tools does not support commands on class library projects in ASP.NET Core and .NET Core applications. See http://go.microsoft.com/fwlink/?LinkId=798221 for details and workarounds.  

or if you forgot to add the [STAThread]...static void main(string[] args) in you're Program.cs:
 PM> Scaffold-DbContext "Server=localhost;Database=VbscriptIndexer;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer  
 C:\Program Files\dotnet\dotnet.exe compile-csc @C:\Projects\dotNetCore\Core.Datav2\bin\Core.Datav2\obj\Debug\netcoreapp1.0\dotnet-compile.rsp returned Exit Code 1 C:\Projects\dotNetCore\Core.Datav2\error CS5001: Program does not contain a static 'Main' method suitable for an entry point   
  Build failed on 'Core.Datav2'.   
And if you're still having issues, re-install the .NET Core SDK Install (Preview 2) and try again. I ended up doing it a few times which was a bit annoying but was really self-caused misery.

Saturday, July 2, 2016

Visual Studio VS.Net 2015 RC2 and Typescript

So my Visual Studio solution is throwing a ton of errors due to the latest rx.js component. The Angular2 solution works just fine, VS.Net 2015 RC2 doesn't think so. To resolve the VS 2015 RC2 issue, you can see the fix described at:
https://github.com/Microsoft/TypeScript/issues/8518

This link essentially upgrades your VS.Net 2015 RC2 instances from ts.version 1.8.9 to ts.version 1.8.10 which will fix all the pesky ambient declaration and other similar errors showing up in Visual Studio. 1.8.10 now handles external modules with their nested ambient modules by moving them to imported files since they need to be resolved. As an aside, I found that typings.json resolves much the same issue but in another way.

If you have VS.2015 rc2 you should seriously consider upgrading it with update 3: https://blogs.msdn.microsoft.com/visualstudio/2016/06/27/visual-studio-2015-update-3-and-net-core-1-0-available-now/

Update 3 will take you to ts.version 1.8.34 and should NOT install the ts version 1.8.10 over the top.

Anyways, after installing v 1.8.10 my VS.Net rc2 Angular2 app builds successfully. Will install update 3 tomorrow as it is a 7gb download and can take quite a while to install.

Tuesday, June 14, 2016

Exploring Microservices and Web Components

Been listening to a number of podcasts and reading on microservices over the last couple years and may now have a project to apply this pattern to.

Found some good posts on the subject:

1. Microservices vs Monolithic:
http://www.slideshare.net/chris.e.richardson/decompose-that-war-a-pattern-language-for-microservices-qcon-qconsp/20

2. API gateway pattern to support microservices:
http://microservices.io/patterns/apigateway.html

3. Frontend microservices (aka Web Components)
https://technologyconversations.com/2015/08/09/including-front-end-web-components-into-microservices/

3.a. Web Components are great except perhaps in IE 11 which has the Polyfill workaround. So it's definitely doable there. IE Edge appears to be being built with Web Components in mind so we'll see how that future plays out. Working in an enterprise that relies on IE as it's default browser, one has to consider such things.
http://microservices.io/patterns/apigateway.html on IE Edge
https://vaadin.com/blog/-/blogs/web-components-in-production-use-are-we-there-yet-/ on IE 11

Saturday, June 4, 2016

Visual Studio 2015 Update 2 NuGet.config Proxy/Firewall Issues

Overview
My "dotnet restore" does not work with NuGet's v3 package source.  This post analyzes why it was occurring and how it was resolved.

Analysis:
I've been playing around with my nuget.config file recently due to "dotnet restore" issues with a project built with VS 2015 Update 2 dotnetcore project. To start, nuget.config is located here for me: C:\Users\<username>\AppData\Roaming\NuGet\NuGet.Config

When I change this file it affects my VS 2015 builds (i.e. restore)

For the purposes of this post I will be using the command line to do "dotnet restore"s using ConEmu.
I was having issues with a couple of the package sources in nuget.config requiring proxy authentication. Here is a sample ran from the command line:
$ dotnet restore
log  : Restoring packages for C:\<projectPath>\project.json...
info :   GET https://api.nuget.org/v3-flatcontainer/microsoft.netcore.dotnethostresolver/index.json
info :   OK https://api.nuget.org/v3-flatcontainer/microsoft.netcore.dotnethostresolver/index.json 250ms
error: Unable to load the service index for source https://dotnet.myget.org/F/dotnet-cli/api/v3/index.json.
error:   Response status code does not indicate success: 407 (Proxy Authentication Required).

So I reverted back to an earlier version of NuGet.Config which is as follows:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <activePackageSource>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  </activePackageSource>
  <packageSources>
    <add key="nuget.org" value="https://www.nuget.org/api/v2/" />
  </packageSources>
</configuration>

Now when I run "dotnet restore" from the command line I see this:
$ dotnet restore
log  : Restoring packages for C:\<projectPath>\project.json...
info :   GET https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NETCore.DotNetHostResolver'
info :   OK https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NETCore.DotNetHostResolver' 807ms
info :   GET https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NETCore.DotNetHost'
info :   OK https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NETCore.DotNetHost' 136ms
log  : Restoring packages for tool 'Microsoft.AspNetCore.Server.IISIntegration.Tools' in C:\<projectPath>\project.json...
info : Committing restore...
log  : Writing lock file to disk. Path: C:\<projectPath>\project.lock.json
log  : C:\<projectPath>\project.json
log  : Restore completed in 9030ms.

NuGet Config files used:
    C:\Users\<user>\AppData\Roaming\NuGet\NuGet.Config
    C:\ProgramData\nuget\Config\Microsoft.VisualStudio.Offline.config

Feeds used:
    https://www.nuget.org/api/v2/
    C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\

I like the command line tool "dotnet restore" and the info it provides.  Using it helps see what NuGet Config files are being used and which feeds are being used. Additionally I'm currently using https://www.nuget.org/api/v2/ as a package source where I should be using v3.

For grins and giggles I added "Hangfire.Core", of which I know nothing about, to my project.json to see how it would react:
"Hangfire.Core": "1.5.6"
It looks like the v2 package source found it but unfortunately my project is not compatible with it so...
$ dotnet restore
log  : Restoring packages for C:\<projectPath>\project.json...
info :   CACHE https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NETCore.DotNetHostResolver'
info :   CACHE https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NETCore.DotNetHost'
log  : Restoring packages for tool 'Microsoft.AspNetCore.Server.IISIntegration.Tools' in C:\<projectPath>\project.json...
error: Package Hangfire.Core 1.5.6 is not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0). Package Hangfire.Core 1.5.6 supports: net45 (.NETFramework,Version=v4.5)
error: Package Owin 1.0.0 is not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0). Package Owin 1.0.0 supports: net40 (.NETFramework,Version=v4.0)
error: One or more packages are incompatible with .NETCoreApp,Version=v1.0.
info : Committing restore...
log  : Lock file has not changed. Skipping lock file write. Path: C:\<projectPath>\project.lock.json
log  : C:\<projectPath>\project.json
log  : Restore failed in 1219ms.

Errors in C:\<projectPath>\project.json
    Package Hangfire.Core 1.5.6 is not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0). Package Hangfire.Core 1.5.6 supports: net45 (.NETFramework,Version=v4.5)
    Package Owin 1.0.0 is not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0). Package Owin 1.0.0 supports: net40 (.NETFramework,Version=v4.0)
    One or more packages are incompatible with .NETCoreApp,Version=v1.0.

NuGet Config files used:
    C:\Users\<user>\AppData\Roaming\NuGet\NuGet.Config
    C:\ProgramData\nuget\Config\Microsoft.VisualStudio.Offline.config

Feeds used:
    https://www.nuget.org/api/v2/
    C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\

What's weird is that v2 works at all for me. Granted I have VS 2010, 2012, 2013, and 2015 on my machine. Here is what I found from the nuget homepage:
•NuGet feed v3 (VS 2015 / NuGet v3.x): https://api.nuget.org/v3/index.json
•NuGet feed v2 (VS 2013 and earlier / NuGet 2.x): https://www.nuget.org/api/v2
So once more into the breach..... (i.e. get v3 to work for my "dotnet restore"s in VS 2015)

I changed the project.json to see if "Hangfire.Core" is supported by dotnetcore in it's current beta release:
"Hangfire.Core": "1.6.0-beta3"

I also modified my NuGet.Config as follows to include the v3 version:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <activePackageSource>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  </activePackageSource>
  <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    <add key="nuget.org" value="https://www.nuget.org/api/v2/" />
  </packageSources>
</configuration>

However when I run "dotnet restore" it fails with the above NuGet.Config file:
$ dotnet restore
log  : Restoring packages for C:\<projectPath>\project.json...
error: Unable to load the service index for source https://api.nuget.org/v3/.
error:   An error occurred while sending the request.
error:   A connection with the server could not be established

Resolution:
Ultimately removing the activePackageSources section fixed the error for me and allowed me to pick up v3 finally as a valid package source. Here is the new NuGet.Config that works:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    <add key="nuget.org" value="https://www.nuget.org/api/v2/" />
  </packageSources>
</configuration>

And here are the command line results, although again "Hangfire.Core" in it's current beta state is not compatible with dotnetcore. But hey, at least the feed is now using v3:
$ dotnet restore
log  : Restoring packages for C:\<projectPath>\project.json...
info :   GET https://api.nuget.org/v3-flatcontainer/microsoft.netcore.dotnethostresolver/index.json
info :   GET https://api.nuget.org/v3-flatcontainer/hangfire.core/index.json
info :   OK https://api.nuget.org/v3-flatcontainer/microsoft.netcore.dotnethostresolver/index.json 168ms
info :   GET https://api.nuget.org/v3-flatcontainer/microsoft.netcore.dotnethost/index.json
info :   OK https://api.nuget.org/v3-flatcontainer/microsoft.netcore.dotnethost/index.json 182ms
info :   OK https://api.nuget.org/v3-flatcontainer/hangfire.core/index.json 578ms
info :   GET https://api.nuget.org/v3-flatcontainer/hangfire.core/1.6.0-beta3/hangfire.core.1.6.0-beta3.nupkg
info :   OK https://api.nuget.org/v3-flatcontainer/hangfire.core/1.6.0-beta3/hangfire.core.1.6.0-beta3.nupkg 215ms
log  : Installing Hangfire.Core 1.6.0-beta3.
log  : Restoring packages for tool 'Microsoft.AspNetCore.Server.IISIntegration.Tools' in C:\<projectPath>\project.json...
error: Package Hangfire.Core 1.6.0-beta3 is not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0). Package Hangfire.Core 1.6.0-beta3 supports: net45 (.NETFramework,Version=v4.5)
error: Package Owin 1.0.0 is not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0). Package Owin 1.0.0 supports: net40 (.NETFramework,Version=v4.0)
error: One or more packages are incompatible with .NETCoreApp,Version=v1.0.
info : Committing restore...
log  : Writing lock file to disk. Path: C:\<projectPath>\project.lock.json
log  : C:\<projectPath>\project.json
log  : Restore failed in 5477ms.

Errors in C:\<projectPath>\project.json
    Package Hangfire.Core 1.6.0-beta3 is not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0). Package Hangfire.Core 1.6.0-beta3 supports: net45 (.NETFramework,Version=v4.5)
    Package Owin 1.0.0 is not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0). Package Owin 1.0.0 supports: net40 (.NETFramework,Version=v4.0)
    One or more packages are incompatible with .NETCoreApp,Version=v1.0.

NuGet Config files used:
    C:\Users\<user>\AppData\Roaming\NuGet\NuGet.Config
    C:\ProgramData\nuget\Config\Microsoft.VisualStudio.Offline.config

Feeds used:
    https://api.nuget.org/v3/index.json
    C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\

So I came at this from a couple different directions and ultimately got v3 to work.

To throw a wrench into this solution:
So I continued to have issues connecting to the nuget v2 and v3 package sources via "dotnet restore". Most of the time it doesn’t work, sometimes it works. I’m thinking that perhaps my company has multiple proxy servers out there filtering our requests out to the world. I’m thinking our requests out to the world go through one of these servers. Sometimes we’re going through one server for a while when suddenly we are on another server. My guess is that one of these servers lets us through while another doesn’t allow it. I tested it by simply running "dotnet restore" from the command line over and over again. Mostly it failed but it would sometimes work:

 <user>@<computer> C:\<projectPath>  
 $ dotnet restore  
 log : Restoring packages for C:\<projectPath>\project.json...  
 info :  GET https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NETCore.DotNetHostResolver'  
 info :  OK https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NETCore.DotNetHostResolver' 733ms  
 info :  GET https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NETCore.DotNetHost'  
 info :  OK https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NETCore.DotNetHost' 186ms  
 log : Restoring packages for tool 'Microsoft.AspNetCore.Server.IISIntegration.Tools' in C:\<projectPath>\project.json...  
 info : Committing restore...  
 log : Writing lock file to disk. Path: C:\<projectPath>\project.lock.json  
 log : C:\<projectPath>\project.json  
 log : Restore completed in 11027ms.  
 NuGet Config files used:  
   C:\Users\<user>\AppData\Roaming\NuGet\NuGet.Config  
   C:\ProgramData\nuget\Config\Microsoft.VisualStudio.Offline.config  
 Feeds used:  
   https://www.nuget.org/api/v2/  
   C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\  
 <user>@<computer> C:\<projectPath>  
 $ dotnet restore  
 log : Restoring packages for C:\<projectPath>\project.json...  
 error: Unable to load the service index for source https://api.nuget.org/v2/index.json.  
 error:  An error occurred while sending the request.  
 error:  A connection with the server could not be established  
 <user>@<computer> C:\<projectPath>  
 $ dotnet restore  
 log : Restoring packages for C:\<projectPath>\project.json...  
 error: Unable to load the service index for source https://api.nuget.org/v3/index.json.  
 error:  An error occurred while sending the request.  
 error:  A connection with the server could not be established  
 <user>@<computer> C:\<projectPath>  
 $ dotnet restore  
 log : Restoring packages for C:\<projectPath>\project.json...  
 error: Unable to load the service index for source https://api.nuget.org/v3/index.json.  
 error:  An error occurred while sending the request.  
 error:  A connection with the server could not be established  
 <user>@<computer> C:\<projectPath>  
 $ dotnet restore  
 log : Restoring packages for C:\<projectPath>\project.json...  
 error: Unable to load the service index for source https://api.nuget.org/v3/index.json.  
 error:  An error occurred while sending the request.  
 error:  A connection with the server could not be established  
 <user>@<computer> C:\<projectPath>  
 $ dotnet restore  
 log : Restoring packages for C:\<projectPath>\project.json...  
 error: Unable to load the service index for source https://api.nuget.org/v3/index.json.  
 error:  An error occurred while sending the request.  
 error:  A connection with the server could not be established  
 <user>@<computer> C:\<projectPath>  
 $ dotnet restore  
 log : Restoring packages for C:\<projectPath>\project.json...  
 error: Unable to load the service index for source https://api.nuget.org/v3/index.json.  
 error:  An error occurred while sending the request.  
 error:  A connection with the server could not be established  
 <user>@<computer> C:\<projectPath>  
 $ dotnet restore  
 log : Restoring packages for C:\<projectPath>\project.json...  
 error: Unable to load the service index for source https://api.nuget.org/v3/index.json.  
 error:  An error occurred while sending the request.  
 error:  A connection with the server could not be established  
 <user>@<computer> C:\<projectPath>  
 $ dotnet restore  
 log : Restoring packages for C:\<projectPath>\project.json...  
 info :  GET https://api.nuget.org/v3-flatcontainer/microsoft.netcore.dotnethostresolver/index.json  
 info :  OK https://api.nuget.org/v3-flatcontainer/microsoft.netcore.dotnethostresolver/index.json 189ms  
 info :  GET https://api.nuget.org/v3-flatcontainer/microsoft.netcore.dotnethost/index.json  
 info :  OK https://api.nuget.org/v3-flatcontainer/microsoft.netcore.dotnethost/index.json 282ms  
 log : Restoring packages for tool 'Microsoft.AspNetCore.Server.IISIntegration.Tools' in C:\<projectPath>\project.json...  
 info : Committing restore...  
 log : Lock file has not changed. Skipping lock file write. Path: C:\<projectPath>\project.lock.json  
 log : C:\<projectPath>\project.json  
 log : Restore completed in 2410ms.  
 NuGet Config files used:  
   C:\Users\<user>\AppData\Roaming\NuGet\NuGet.Config  
   C:\ProgramData\nuget\Config\Microsoft.VisualStudio.Offline.config  
 Feeds used:  
   https://api.nuget.org/v3/index.json  
   C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\  
 <user>@<computer> C:\<projectPath>  
 $  
So we have an issue with our proxy/firewall that resulted in the rigmarole of this post above. Enjoy!

Tuesday, May 24, 2016

Angular2 migration from Beta to RC1

I had a chance to explore this Angular2 space again and found that voila, RC1 is out! How fun it would be migrate over.. Using my last post as a basis for moving forward, here is what I went through.

Please note that I'm not an expert in Angular2. Just exploring it in my free time.

First off the dependencies in your packages.json file changed:
Before:
 {  
  "version": "1.0.0",  
  "name": "ASP.NET",  
  "private": true,  
  "dependencies": {  
   "angular2": "^2.0.0-beta.7",  
   "es6-promise": "^3.1.2",  
   "es6-shim": "0.35.0",  
   "reflect-metadata": "^0.1.3",  
   "rxjs": "^5.0.0-beta.2",  
   "systemjs": "^0.19.23",  
   "whatwg-fetch": "^0.11.0",  
   "zone.js": "^0.6.1"  
  },  
  "devDependencies": {}  
 }  

After:
 {  
  "version": "1.0.0",  
  "name": "ASP.NET",  
  "private": true,  
  "dependencies": {  
   "@angular/common": "2.0.0-rc.1",  
   "@angular/compiler": "2.0.0-rc.1",  
   "@angular/core": "2.0.0-rc.1",  
   "@angular/http": "2.0.0-rc.1",  
   "@angular/platform-browser": "2.0.0-rc.1",  
   "@angular/platform-browser-dynamic": "2.0.0-rc.1",  
   "@angular/router": "2.0.0-rc.1",  
   "@angular/router-deprecated": "2.0.0-rc.1",  
   "@angular/upgrade": "2.0.0-rc.1",  
   "es6-promise": "^3.1.2",  
   "es6-shim": "0.35.0",  
   "reflect-metadata": "^0.1.3",  
   "rxjs": "^5.0.0-beta.6", //Be sure to use beta.6  
   "systemjs": "^0.19.27",  
   "whatwg-fetch": "^0.11.0",  
   "zone.js": "^0.6.12"  
  },  
  "devDependencies": {  
   "typescript": "^1.8.10"  
  }  
 }  

After setting up these dependencies in packages.json I performed my npm install and found some errors:

Went ahead and deleted the "angular2" folders from my "wwwroot" folder.
Modified the gulpfile.js file to replace the "angular2" copies from node_modules to wwwroot/node_modules with new "@angular/*" calls:
 gulp.task('thirdparty', function () {  
   gulp.src('./node_modules/@angular/**/*.js')  
     .pipe(gulp.dest('./wwwroot/node_modules/@angular'));  
   // gulp.src('./node_modules/angular2/**/*.js')  
   //   .pipe(gulp.dest('./wwwroot/node_modules/angular2'));  

Then I had to go and update my index.html file to replace the angular2 references with @angular. However I decided life would be harder if I took this opportunity to see what systemjs is about. So of course lets digress and go down systemjs learning alley.

Systemjs allows us to specify our third party references in a separate javascript file. Systemjs has the added ability of loading these 3rd party references on demand vs on page load. So anyways, here is the before and after of my index.html file: Before:
 <!DOCTYPE html>  
 <html>  
 <head>  
   <base href="/">  
   <meta charset="utf-8" />  
   <title></title>  
 </head>  
 <body>  
   <app-shell><h2>Loading...</h2></app-shell>  
   <script src="node_modules/es6-shim/es6-shim.js"></script>  
   <script src="node_modules/angular2/es6/dev/src/testing/shims_for_IE.js"></script>  
   <script src="node_modules/systemjs/dist/system.src.js"></script>  
   <script src="node_modules/rxjs/bundles/Rx.js"></script>  
   <script src="node_modules/es6-shim/es6-shim.js"></script>  
   <script src="node_modules/angular2/bundles/angular2.dev.js"></script>  
   <script src="node_modules/angular2/bundles/router.dev.js"></script>  
   <script src="node_modules/angular2/bundles/http.dev.js"></script>  
   <script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>  
   <script>  
     System.config({  
       packages: {  
         app: {  
           format: 'register',  
           defaultExtension: 'js',  
         }  
       }  
     });  
     System.import('app/boot')  
       .then(console.log('started application'), console.error.bind(console));  
   </script>  
 </body>  
 </html>  

After:
 <!DOCTYPE html>  
 <html>  
 <head>  
   <base href="/">  
   <meta charset="utf-8" />  
   <title></title>  
 </head>  
 <body>  
   <app-shell><h2>Loading...</h2></app-shell>  
   <script src="node_modules/es6-shim/es6-shim.js"></script>  
   <script src="node_modules/typescript/lib/typescript.js"></script>  
   <script src="node_modules/es6-shim/es6-shim.js"></script>  
   <script src="node_modules/reflect-metadata/Reflect.js"></script>  
   <script src="node_modules/systemjs/dist/system.js"></script> <!--//Changed from system.src.js -->  
   <script src="node_modules/zone.js/dist/zone.js"></script>   <!--//Had to add Zonejs as it is used by @angular/core -->  
   <script src="systemjs.config.js"></script>  
   <script>  
     System.import('app/boot')  
       .then(console.log('started application'), console.error.bind(console));  
   </script>  
 </body>  
 </html>  

This leads us to where are the "@angular" references? Well I've got them in a file called systemjs.config.js which is in the root of my project directory (i.e. at the same level as my packages.json, etc).
Here is what I've got in my systemjs.config.js file:
 System.config({  
   transpiler: 'typescript',  
   typescriptOptions: {emitDecoratorMetadata: true},  
   map: {  
     'app' : 'app',  
     'rxjs': 'node_modules/rxjs',  
     '@angular/core'          : 'node_modules/@angular/core',  
     '@angular/common'         : 'node_modules/@angular/common',  
     '@angular/compiler'        : 'node_modules/@angular/compiler',  
     '@angular/router'         : 'node_modules/@angular/router',  
     '@angular/platform-browser'    : 'node_modules/@angular/platform-browser',  
     '@angular/platform-browser-dynamic': 'node_modules/@angular/platform-browser-dynamic',  
     '@angular/http'          : 'node_modules/@angular/http'  
 },  
   packages: {  
     'app'               : {main: 'app/boot.ts', defaultExtension: 'ts'},  
     'rxjs'               : {main: 'index.js'},  
     '@angular/core'          : {main: 'index.js'},  
     '@angular/common'         : {main: 'index.js'},  
     '@angular/compiler'        : {main: 'index.js'},  
     '@angular/router'         : {main: 'index.js'},  
     '@angular/platform-browser'    : {main: 'index.js'},  
     '@angular/platform-browser-dynamic': {main: 'index.js'},  
     '@angular/http'          : { main: 'index.js'}  
 }  
 });  

So I've got my app, rxjs and @angular setup in systemjs and it seems to work just fine. But before it will work you need to be sure to copy it to the wwwroot folder via your gulpfile.js:
 gulp.task('copy', function () {  
   gulp.src('./app/**/*.*')  
     .pipe(gulp.dest('./wwwroot/app'));  
   gulp.src('./systemjs.config.js')  
     .pipe(gulp.dest('./wwwroot'));  
 });  

So our basic setup is done. Now onto the interesting changes that have taken place since Angular2 Beta 7: 1. It looks like @View is no more. They've moved it's properties into @Componment. Here is some before and after: Before:
 @Component({  
   selector: 'book-edit.component'  
 })  
 @View({  
   templateUrl: './app/components/book/edit/book-edit.component.html',  
   directives: [CORE_DIRECTIVES, FORM_DIRECTIVES, NgFormControl]  
 })  

After:
 @Component({  
   selector: 'book-edit.component',  
   templateUrl: './app/components/book/edit/book-edit.component.html',  
   directives: [CORE_DIRECTIVES, FORM_DIRECTIVES, NgFormControl]  
 })  

2. Of course, with angular2 gone, you have to go through and clean up all your imports. Here is a brief example: Before:
 import {Component, View, Inject} from 'angular2/core';  
 import {RouteParams} from 'angular2/router';  
 import {CORE_DIRECTIVES, FORM_DIRECTIVES, FormBuilder, Control, ControlGroup, Validators, NgFormControl, AbstractControl } from 'angular2/common';  

After:
 import {Component, Inject} from '@angular/core';  
 import {RouteSegment} from '@angular/router';  
 import {CORE_DIRECTIVES, FORM_DIRECTIVES, FormBuilder, Control, ControlGroup, Validators, NgFormControl, AbstractControl } from '@angular/common';  

3. Routers had a major overhaul. Here are some before and after changes I ran into:
 
 before: import {RouteParams} from '@angular/router';  
 after : import {RouteSegment} from '@angular/router';  

 before: constructor( @Inject(RouteParams) params: RouteParams,  
 after : constructor( @Inject(RouteSegment) params: RouteSegment,  

 before: this.getBook(params.get('id'));  
 after : this.getBook(params.getParam('id'));  

 before:  
 @RouteConfig([  
     { path: '/list-admin',      component: BookListAdminComponent,  as: 'ListAdmin' },  
     { path: '/list-readonly',     component: BookListReadonlyComponent, as: 'ListReadonly' },  
     { path: '/create',        component: BookCreateComponent,    as: 'Create' },  
     { path: '/edit/:id',       component: BookEditComponent,     as: 'Edit' },  
     { path: '/view/:id/',       component: BookViewComponent,     as: 'View' }  
 ])  
 after:   
 @Routes([  
     { path: '/list-admin', component: BookListAdminComponent }, //  as: 'ListAdmin' },  
     { path: '/list-readonly', component: BookListReadonlyComponent }, // as: 'ListReadonly' },  
     { path: '/create', component: BookCreateComponent }, //    as: 'Create' },  
     { path: '/edit/:id', component: BookEditComponent }, //     as: 'Edit' },  
     { path: '/view/:id', component: BookViewComponent }, //     as: 'View' }  
 ])  

 before: this.router.parent.navigate(['/View', { id: book.id }]);  
 after: this.router.navigate(['/view/'+ book.id ]);  

 before: <a [routerLink]="['ListReadonly']">View List of Books</a>  
 after: <a [routerLink]="['/list-readonly']">View List of Books</a>  
Now at this point I've made all my import changes, etc and think I'm ready to continue on. Unfortunately, VS.Net 2015 is throwing a lot of errors my way now, like:
1. Observable does not contain property ‘map’
2. TS2304: Cannot find name 'Promise'
3. Build: Ambient modules cannot be nested in other modules or namespaces
4. Build: Ambient declaration cannot specify relative module name

Looking at the details of these errors, for the most part all the errors I'm seeing are all associated to rxjs.

In my little world I've been brought up to respect and bow before the VS.Net 2015 gods when they throw red error lightning bolts my way. In this case its about 650 of 'em and I'm resembling a pin cushion. For I must fix them before I proceed, so I did the following: (note: I found later on that the code would run fine. It was VS.net and it's typescript version that were the problem and there is nothing I can do about it at this point...)
1. Explored 'typings'
2. Explored more 'gulp' functionality
3. In the end not sure if I needed 'typings' and didn't need the additional 'gulp' functionality.

I'll explore my journey with 'typings' in another post.

So yeah, life is good again. VS.net is throwing errors, but when I run the app all is good. All my crud functionality is working again after the upgrade. I look forward to when VS.net stops throwing errors on the rxjs stuff. So we'll see.