Software Architect at Genzeon Corporation in Malvern, Pennsylvania, Microsoft .NET MVP, Husband, Dad and Geek.
8937 stories
·
22 followers

.NET Core - Cross-Platform Code Generation with Roslyn and .NET Core

1 Share

.NET Core is the modular, open source and cross-platform set of tools that allows you to build next-generation .NET applications, which run on Windows, Linux and macOS (microsoft.com/net/core/platform). It can also be installed on the Windows 10 for IoT distribution, and it runs on devices such as the Raspberry PI. .NET Core is a powerful platform that includes the runtime, libraries, and compilers, with full support for languages such as C#, F#, and Visual Basic. This means you can code in C# not only on Windows, but also on different OSes because the .NET Compiler Platform (github.com/dotnet/roslyn), also referred to as “Project Roslyn,” provides open source, cross-platform compilers with rich code analysis APIs. As an important implication, you can leverage the Roslyn APIs to perform many code-related operations on different OSes, such as code analysis, code generation and compilation. This article walks through the necessary steps to set up a C# project on .NET Core to use the Roslyn APIs and explains some interesting code-generation and compilation scenarios. It also discusses some basic Reflection techniques to invoke and run code compiled with Roslyn on .NET Core. If you’re unfamiliar with Roslyn, you’ll want to read the following articles first:

Installing the .NET Core SDK

The first step is installing .NET Core and the SDK. If you work on Windows and you’ve installed Visual Studio 2017, .NET Core is already included if the .NET Core cross-platform development workload was selected at installation time in the Visual Studio Installer. If not, simply open the Visual Studio Installer, select the workload and click Modify. If you’re working on Windows but not relying on Visual Studio 2017, or you’re working on Linux or macOS, you can install .NET Core manually and use Visual Studio Code as the development environment (code.visualstudio.com). The latter is the scenario I’ll discuss in this article, as Visual Studio Code is cross-platform itself; thus, it’s a great companion for .NET Core. Also, remember to install the C# extension for Visual Studio Code (bit.ly/29b1Ppl). The steps to install .NET Core are different depending on the OS, so follow the instructions at bit.ly/2mJArWx. Make sure you install the latest release. It’s worth mentioning that the latest releases of .NET Core no longer support the project.json file format, but instead support the more common .csproj file format with MSBuild.

Scaffolding a .NET Core Application in C#

With .NET Core, you can create Console applications and Web applications. For Web applications, Microsoft is making more templates available, besides the ASP.NET Core template, as .NET Core goes forward on its roadmap. Because Visual Studio Code is a lightweight editor, it doesn’t provide project templates as Visual Studio does. This means you need to create an application from the command line inside a folder whose name will also be the application name. The following example is based on instructions for Windows, but the same concepts apply to macOS and Linux. To get started, open a command prompt and move to a folder on your disk. For instance, say you have a folder called C:\Apps, go to this folder and create a new subfolder called RoslynCore, using the following commands:

> cd C:\Apps
> md RoslynCore
> cd RoslynCore

Therefore, RoslynCore will be the name of the sample application discussed in this article. It will be a Console application, which is perfect for instructional purposes and simplifies the approach to coding with Roslyn. You can also use the same techniques in ASP.NET Core Web applications. To create a new, empty project for a Console application, simply type the following command line:

In this way, .NET Core scaffolds a C# project for a Console application called RoslynCore. Now you can open the project’s folder with Visual Studio Code. The easiest way is typing the following command line:

Of course, you could open Visual Studio Code from the Windows Start menu and then open a project folder manually. Once you enter any C# code file, it will ask your permission to generate some required assets and to restore some NuGet packages (see Figure 1).

Visual Studio Code Needs to Update the Project
Figure 1 Visual Studio Code Needs to Update the Project

The next step is adding the NuGet packages necessary for working with Roslyn.

Adding the Roslyn NuGet Packages

As you might know, the Roslyn APIs can be consumed by installing some NuGet packages from the Microsoft.CodeAnalysis hierarchy. Before installing these packages, it’s important to clarify how the Roslyn APIs fit into the .NET Core system. If you’ve ever worked with Roslyn on the .NET Framework, you might be used to taking advantage of the full set of Roslyn APIs. .NET Core relies on .NET Standard libraries, which means that only the Roslyn libraries that support .NET Standard can be consumed in .NET Core. At the time of this writing, most of the Roslyn APIs are already available to .NET Core, including (but not limited to) the Compiler APIs  (with the Emit and Diagnostic APIs) and the Workspaces APIs. Only a few APIs are not yet portable, but Microsoft is investing hugely in Roslyn and .NET Core, so it’s reasonable to expect full .NET Standard compatibility in future releases. A real-world example of a cross-platform application that runs on .NET Core is OmniSharp (bit.ly/2mpcZeF), which leverages the Roslyn APIs to empower most of the code editor features, such as completion lists and syntax highlighting.

In this article, you’ll see how to leverage the Compiler and the Diagnostic APIs. To accomplish this, you need to add the Microsoft.CodeAnalysis.CSharp NuGet package to your project. With the new .NET Core project system based on MSBuild, the list of NuGet packages is now included in the .csproj project file. In Visual Studio 2017, you can use the client UI for NuGet to download, install and manage packages, but in Visual Studio Code there’s no equivalent option. Fortunately, you can simply open the .csproj file and locate the <ItemGroup> node that contains <PackageReference> elements, each representing a required NuGet package. Modify the node as follows:

<ItemGroup>
  ...
  <PackageReference Include="Microsoft.CodeAnalysis.CSharp"
    Version="2.0.0 " />
  <PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
</ItemGroup>

Note that adding a reference to the Microsoft.CodeAnalysis.C­Sharp package allows you to access the C# compiler’s APIs, and that the System.Runtime.Loader package is required for Reflection and will be used later in the article.

When you save your changes, Visual Studio Code will detect missing NuGet packages and will offer to restore them.

Code Analysis: Parsing Source Text and Generating Syntax Nodes

The first example is about code analysis, and demonstrates how to parse source code text and generate new syntax nodes. For instance, imagine you have the following simple business object and you want to generate a View Model class based on it:

namespace Models
{
  public class Item
  {
    public string ItemName { get; set }
  }
}

The text for this business object might come from different sources, such as a C# code file or a string in your code or even from user input. With the code analysis APIs, you can parse the source text and generate a new syntax node that the compiler can understand and manipulate. For example, consider the code shown in Figure 2, which parses a string containing a class definition, gets its corresponding syntax node and calls a new static method that generates a View Model from the syntax node.

Figure 2 Parsing Source Code and Retrieving a Syntax Node

using System;
using RoslynCore;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
class Program
{
  static void Main(string[] args)
  {
    GenerateSampleViewModel();
  }
  static void GenerateSampleViewModel()
  {
    const string models = @"namespace Models
{
  public class Item
  {
    public string ItemName { get; set }
  }
}
";
    var node = CSharpSyntaxTree.ParseText(models).GetRoot();
    var viewModel = ViewModelGeneration.GenerateViewModel(node);
    if(viewModel!=null)
      Console.WriteLine(viewModel.ToFullString());
    Console.ReadLine();
  }
}

The GenerateViewModel method is going to be defined in a static class called ViewModelGeneration, so add a new file called ViewModelGeneration.cs to the project. The method looks for a class definition in the input syntax node (for demonstration purposes, the first instance of a ClassDeclarationSyntax object), then constructs a new View Model based on the class’s name and members. Figure 3 demonstrates this.

Figure 3 Generating a New Syntax Node

using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
namespace RoslynCore
{
  public static class ViewModelGeneration
  {
    public static SyntaxNode GenerateViewModel(SyntaxNode node)
    {
      // Find the first class in the syntax node
      var classNode = node.DescendantNodes()
       .OfType<ClassDeclarationSyntax>().FirstOrDefault();
      if(classNode!=null)
      {
        // Get the name of the model class
        string modelClassName = classNode.Identifier.Text;
        // The name of the ViewModel class
        string viewModelClassName = $"{modelClassName}ViewModel";
        // Only for demo purposes, pluralizing an object is done by
        // simply adding the "s" letter. Consider proper algorithms
        string newImplementation =
          $@"public class {viewModelClassName} : INotifyPropertyChanged
{{
public event PropertyChangedEventHandler PropertyChanged;
// Raise a property change notification
protected virtual void OnPropertyChanged(string propname)
{{
  PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));
}}
private ObservableCollection<{modelClassName}> _{modelClassName}s;
public ObservableCollection<{modelClassName}> {modelClassName}s
{{
  get {{ return _{modelClassName}s; }}
  set
  {{
    _{modelClassName}s = value;
    OnPropertyChanged(nameof({modelClassName}s));
  }}
}}
public {viewModelClassName}() {{
// Implement your logic to load a collection of items
}}
}}
";
          var newClassNode =
            CSharpSyntaxTree.ParseText(newImplementation).GetRoot()
            .DescendantNodes().OfType<ClassDeclarationSyntax>()
            .FirstOrDefault();
          // Retrieve the parent namespace declaration
          if(!(classNode.Parent is NamespaceDeclarationSyntax)) return null;
          var parentNamespace = (NamespaceDeclarationSyntax)classNode.Parent;
          // Add the new class to the namespace and adjust the white spaces
          var newParentNamespace =
            parentNamespace.AddMembers(newClassNode).NormalizeWhitespace();
          return newParentNamespace;
        }
      }
      else
      {
        return null;
      }
    }
  }
}

In the first part of the code in Figure 3, you can see how the View Model is first represented as a string, with string interpolation that makes it easy to specify object and member names based on the original class name. In this sample scenario, plurals are generated just by adding an “s” to the object/member name; in real-world code you should use more specific pluralization algorithms.

In the second part of Figure 3, the code invokes CSharpSyntaxTree.ParseText to parse the source text into a SyntaxTree. GetRoot is invoked to retrieve the SyntaxNode for the new tree; with DescendantNodes().OfType<ClassDeclarationSyntax>(), the code retrieves only the syntax nodes that represent a class, selecting only the first one with FirstOrDefault. Retrieving the first class in the syntax node is enough to get the parent namespace where the new View Model class will be inserted. Obtaining a namespace is possible by casting the Parent property of a ClassDeclarationSyntax into a NamespaceDeclarationSyntax object. Because a class could be nested into another class, the code first checks for this possibility by verifying that Parent is of type NamespaceDeclarationSyntax. The final piece of the code adds the new syntax node for the View Model class to the parent namespace, returning this as a syntax node. If you now press F5, you’ll see the result of the code generation in the Debug Console, as shown in Figure 4.

The View Model Class Has Been Correctly Generated
Figure 4 The View Model Class Has Been Correctly Generated

The generated View Model class is a SyntaxNode that the C# compiler can work with, so it can be further manipulated, analyzed for diagnostic information, compiled into an assembly with the Emit APIs and utilized via Reflection.

Getting Diagnostic Information

Whether source text comes from a string, a file or user input, you can take advantage of the Diagnostic APIs to retrieve diagnostic information about code issues such as errors and warnings. Remember that the Diagnostic APIs not only allow for retrieving errors and warnings, they also allow writing analyzers and code refactorings. Continuing the previous example, it’s a good idea to check for syntactic errors in the original source text before attempting to generate a View Model class. To accomplish this, you can invoke the SyntaxNode.GetDiagnostics method, which returns an IEnumerable<Microsoft.CodeAnalysis.Diagnostic> object, if any. Take a look at Figure 5, which offers an extended version of the ViewModelGeneration class. The code checks if the result of invoking GetDiagnostics contains any diagnostics. If not, the code generates the View Model class. If instead the result contains a collection of diagnostics, the code shows information for each diagnostic and returns null. The Diagnostic class provides very granular information about each code issue; for example, the Id property returns a diagnostic id; the GetMessage method returns the full diagnostic message; GetLineSpan returns the diagnostic position in the source code; and the Severity property returns the diagnostic severity, such as Error, Warning or Information.

Figure 5 Checking for Code Issues with the Diagnostic APIs

using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using System;
namespace RoslynCore
{
  public static class ViewModelGeneration
  {
    public static SyntaxNode GenerateViewModel(SyntaxNode node)
    {
      // Find the first class in the syntax node
      var classNode =
        node.DescendantNodes().OfType<ClassDeclarationSyntax>().FirstOrDefault();
      if(classNode!=null)
      {
        var codeIssues = node.GetDiagnostics();
        if(!codeIssues.Any())
        {
          // Get the name of the model class
          var modelClassName = classNode.Identifier.Text;
          // The name of the ViewModel class
          var viewModelClassName = $"{modelClassName}ViewModel";
          // Only for demo purposes, pluralizing an object is done by
          // simply adding the "s" letter. Consider proper algorithms
          string newImplementation =
            $@"public class {viewModelClassName} : INotifyPropertyChanged
{{
public event PropertyChangedEventHandler PropertyChanged;
// Raise a property change notification
protected virtual void OnPropertyChanged(string propname)
{{
  PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));
}}
private ObservableCollection<{modelClassName}> _{modelClassName}s;
public ObservableCollection<{modelClassName}> {modelClassName}s
{{
  get {{ return _{modelClassName}s; }}
  set
  {{
    _{modelClassName}s = value;
    OnPropertyChanged(nameof({modelClassName}s));
  }}
}}
public {viewModelClassName}() {{
// Implement your logic to load a collection of items
}}
}}
";
            var newClassNode =
              SyntaxFactory.ParseSyntaxTree(newImplementation).GetRoot()
              .DescendantNodes().OfType<ClassDeclarationSyntax>()
              .FirstOrDefault();
            // Retrieve the parent namespace declaration
            if(!(classNode.Parent is NamespaceDeclarationSyntax)) return null;
            var parentNamespace = (NamespaceDeclarationSyntax)classNode.Parent;
            // Add the new class to the namespace
            var newParentNamespace =
              parentNamespace.AddMembers(newClassNode).NormalizeWhitespace();
            return newParentNamespace;
          }
          else
          {
            foreach(Diagnostic codeIssue in codeIssues)
          {
            string issue = $"ID: {codeIssue.Id}, Message: {codeIssue.GetMessage()},
              Location: {codeIssue.Location.GetLineSpan()},
              Severity: {codeIssue.Severity}";
            Console.WriteLine(issue);
          }
          return null;
        }
      }
      else
      {
        return null;
      }
    }
  }
}

Now, if you introduce some intentional errors into the source text contained in the models variable, inside the GenerateSample­ViewModel method in Program.cs, and then run the application, you’ll be able to see how the C# compiler returns full details about every code issue. Figure 6 shows an example.

Detecting Code Issues with the Diagnostic APIs
Figure 6 Detecting Code Issues with the Diagnostic APIs

It’s worth noting that the C# compiler produces a syntax tree even if it contains diagnostics. Not only does this result in full fidelity with the source text, it also gives developers an option to fix those issues with new syntax nodes.

Executing Code: the Emit APIs

The Emit APIs allow for compiling source code into assemblies. Then, with Reflection you can invoke and execute code. The next example is a combination of code generation, emit and diagnostic detection. Add a new file called EmitDemo.cs to the project, then consider the code listing shown in Figure 7. As you can see, a SyntaxTree is generated from source text that defines a Helper class containing a static method that calculates the area of a circle. The goal is to produce a .dll from this class and execute the CalculateCircleArea method, passing the radius as an argument.

Figure 7 Compiling and Executing Code with Emit APIs and Reflection

using System;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
namespace RoslynCore
{
  public static class EmitDemo
  {
    public static void GenerateAssembly()
    {
      const string code = @"using System;
using System.IO;
namespace RoslynCore
{
 public static class Helper
 {
  public static double CalculateCircleArea(double radius)
  {
    return radius * radius * Math.PI;
  }
  }
}";
      var tree = SyntaxFactory.ParseSyntaxTree(code);
      string fileName="mylib.dll";
      // Detect the file location for the library that defines the object type
      var systemRefLocation=typeof(object).GetTypeInfo().Assembly.Location;
      // Create a reference to the library
      var systemReference = MetadataReference.CreateFromFile(systemRefLocation);
      // A single, immutable invocation to the compiler
      // to produce a library
      var compilation = CSharpCompilation.Create(fileName)
        .WithOptions(
          new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
        .AddReferences(systemReference)
        .AddSyntaxTrees(tree);
      string path = Path.Combine(Directory.GetCurrentDirectory(), fileName);
      EmitResult compilationResult = compilation.Emit(path);
      if(compilationResult.Success)
      {
        // Load the assembly
        Assembly asm =
          AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
        // Invoke the RoslynCore.Helper.CalculateCircleArea method passing an argument
        double radius = 10;
        object result = 
          asm.GetType("RoslynCore.Helper").GetMethod("CalculateCircleArea").
          Invoke(null, new object[] { radius });
        Console.WriteLine($"Circle area with radius = {radius} is {result}");
      }
      else
      {
        foreach (Diagnostic codeIssue in compilationResult.Diagnostics)
        {
          string issue = $"ID: {codeIssue.Id}, Message: {codeIssue.GetMessage()},
            Location: {codeIssue.Location.GetLineSpan()},
            Severity: {codeIssue.Severity}";
          Console.WriteLine(issue);
        }
      }
    }
  }
}

In the first part, the code creates a new compilation that represents a single, immutable invocation to the C# compiler. The CSharpCompilation object allows the creation of an assembly through its Create method, and WithOptions lets you specify what kind of output to produce, in this case DynamicallyLinkedLibrary. AddReferences is used to add any references your code might need; to accomplish this, you must supply a type that has the same references needed by your code. In this particular case, you simply need the same references on which the object type relies. With Get­TypeInfo().Assembly.Location you retrieve the assembly name for the reference, then MetadataReference.CreateFromFile creates a reference to the assembly inside the compilation. In the end, the syntax tree is added to the compilation with AddSyntaxTrees.

In the second part of the code, an invocation to CSharpCompilation.Emit attempts to produce the binary and returns an object of type EmitResult. The latter is very interesting: It exposes a Success property of type bool that indicates whether or not the compilation succeeded, and it also exposes a property called Diagnostics, which returns an immutable array of Diagnostic objects that can be very useful to understand why the compilation failed. In Figure 7, you can easily see how the Diagnostics property is iterated if the compilation fails. It’s important to mention that the output assembly is a .NET Standard Library, so compiling source text will succeed only if the code parsed with Roslyn relies on APIs that are included in .NET Standard.

Now let’s look at what happens if the compilation succeeds. The System.Runtime.Loader namespace, included in the same-named NuGet package you imported at the beginning of the article, exposes a singleton class called Assembly­LoadContext, which exposes a method called LoadFromAssemblyPath. This method returns an instance of the Assembly class, which allows you to use Reflection to first get a reference to the Helper class, then to get a reference to the CalculateCircleArea method, which you can invoke by passing a value for the radius parameter. The MethodInfo.Invoke method receives null as the first argument because CalculateCircleArea is a static method; therefore, you don’t need to pass any type instance. If you now call the GenerateAssembly method from Main in Program.cs, you’ll see the result of this work, as demonstrated in Figure 8, where the result of the calculation is visible in the Debug Console.

The Result of the Invocation via Reflection of Roslyn-Generated Code
Figure 8 The Result of the Invocation via Reflection of Roslyn-Generated Code

As you can imagine, Emit APIs plus Reflection in .NET Core give you great power and flexibility, because you can generate, analyze and execute C# code regardless of the OS. In fact, all of the examples discussed in this article will certainly run not only on Windows, but also on macOS and most of the Linux distributions. Additionally, invoking code from a library can be accomplished using the Roslyn Scripting APIs, so you’re not limited to Reflection.

Wrapping Up

.NET Core allows you to write C# code to create cross-platform applications that run on multiple OSes and devices, and this is because compilers are cross-platform themselves. Roslyn, the .NET Compiler Platform, empowers the C# compiler on .NET Core and allows developers to leverage the rich code analysis APIs to perform code generation, analysis and compilation. This implies that you can automate tasks by generating and executing code on the fly, analyze source text for code issues, and perform a large number of activities on source code—on Windows, macOS, and Linux.


Alessandro Del Sole has been a Microsoft MVP since 2008. Awarded MVP of the Year five times, he has authored many books, eBooks, instructional videos and articles about .NET development with Visual Studio. Del Sole works as a senior .NET developer, focusing on .NET and mobile app development, training and consulting. You can follow him on Twitter: @progalex.

Thanks to the following Microsoft technical expert for reviewing this article: Dustin Campbell
Dustin Campbell is a principal engineer at Microsoft and a member of the C# language design team. Dustin worked on Roslyn from its inception and is currently responsible for the C# extension for Visual Studio Code.

Read the whole story
alvinashcraft
2 hours ago
reply
West Grove, PA
Share this story
Delete

Not your Grandma's Postman

1 Share

If you’re new to Postman, now is the perfect time to get started. The growth of APIs right now is mind-bending.  Organizations are using APIs to communicate internally between technical architectures, consume microservices, and allow programmatic access to data, services, and connected devices.

If you work with APIs, or just like to dabble, chances are good that if you’re not already using Postman, you’ve at least heard of it.  Maybe your grandma told you stories about developing APIs using old-timey Postman when it was first launched in 2013.

While it’s true that Postman gained popularity with most developers knowing it as a way to build and test requests, it’s grown into so much more.  With over 3 million developers using Postman, there’s been no shortage of feedback.  

Developers wanted to sync collections with their teammates, automate testing in continuous integration pipelines, and set up mock servers.  This direct user feedback has dramatically shaped the product roadmap in the last few years.

Maybe you know someone who uses Postman like a grandma, or maybe that's you. Let's take a second look at Postman, and show Grandma what Postman can really do.

In this tutorial, we'll retrieve a picture from NASA, get an auth key from Imgur, and upload the image to Imgur.  Easy, peazy, lemon squeezy.



Send a request


First things first, let’s get a space pic from the NASA API using their demo API key. Start in the Postman request builder. 

1. Method: Select GET from the dropdown menu of HTTP methods.

2. URL: Enter the URL endpoint provided by NASA – https://api.nasa.gov/planetary/apod

3. Parameters: This request will work without adding any parameters, and default to using NASA's demo key.  However, we can choose to add optional query string parameters to our request. Click the Params button to reveal a key-value editor. As you input parameters, they are automatically added to the query string in the URL bar above.

It’s time to send our request.  Hit the blue Send button, and take a look at the response object the NASA endpoints returns.

 


Save to a collection

Now that you’ve made a request, you can see a record of it in your History on the left. The next time you want to send this same request, you could return to your History and click on the request to load it up in the request builder. Better yet, let’s save this request to a collection.

Click the Save button to open a modal prompting you to save the request to a new or existing collection. Now when you go to the Collections tab of the sidebar, you can see your request beneath this new collection.


Create an environment

An environment is simply a set of key-value pairs, with the key as the variable name. Using an environment template allows you to customize your requests using stored variables. In this case, we'll store our private Imgur credentials.

1. Register your Imgur app: Head to Imgur and register a new application. Select OAuth 2 authorization with a callback URL, and add the following Authorization callback URL – https://www.getpostman.com/oauth2/callback. Make a note of your Client ID and Client secret for the next step.

2. Add an environment: Go to the gear icon in the top right to open the MANAGE ENVIRONMENTS modal. Click the Add button to create a new environment. Name your environment, add 2 keys imgurClientId and imgurClientSecret with their respective values from the previous step, and hit Update.

3. Select the environment: From the dropdown in the top right, select the name of your new environment. With this environment selected, we can now access these environment variables.


Get an auth token

We will use Imgur's OAuth 2.0 process to get an access token that allows us to post an image under our Imgur account.

In the Postman app, under a new request, click on the Authorization tab. Select OAuth 2.0, click on the Get New Access Token button, and fill in these values:

Token Name: can be anything

Auth URL: https://api.imgur.com/oauth2/authorize

Access Token URL: https://api.imgur.com/oauth2/token

Client ID: {{imgurClientId}}

Client Secret: {{imgurClientSecret}}

Grant Type: Authorization Code

Request access token locally: checked

Click on Request Token to initiate the OAuth 2.0 flow authorizing the Postman app to connect to your Imgur account.

Once that is completed, we have a choice to make. Imgur access tokens are only valid for 1 month. We could add the access_token value to our environment under a new imgurAccessToken key, the same way we previously added our Imgur credentials to Postman, but we'd have to come back in a month and update our key.

Instead, let's future-proof the authorization process by creating a second request in our collection to make sure we always have a valid token. Add the refresh_token value to your environment under the imgurRefreshToken key.

Now, we can submit a request using our refresh_token to get a new access_token.

1. Method: POST

2. URL: https://api.imgur.com/oauth2/token

3. Body: Under the Body tab of our second request, add the required parameter values using double curly braces to access our environment variables.

Hit Send.

Under the Tests tab, we can write scripts in JavaScript to execute any logic after the request is sent. Looking closer at the Imgur response object, we can parse the JSON object to retrieve and store our data, like a new access token.

Let’s create an environment variable so we can access this stored value in subsequent requests when the entire collection is run with our environment. Instead of updating our variable by editing the template like we did previously, let's set our environment variable based on the response from this request using Postman’s setEnvironmentVariable() method and pass in our key and value to create a new variable called imgurAccessToken.

Save your updates. The next time this request is sent, a new environment variable called imgurAccessToken will be created and assigned the value of a new access token.  f you haven’t already, save this second request to your collection.


Chain together requests

Besides grouping your requests together in a collection, you can also run a sequence of requests in a collection. It’s time to add a third request to our collection.

Let’s take the picture that we retrieved from NASA, and upload the image to Imgur using the access key we retrieved from Imgur.

1. Method: POST

2. URL: https://api.imgur.com/3/upload

3. Headers: Add the required authorization header using the access token variable we stored in our environment.

4. Body: The Imgur upload photo endpoint requires a single parameter of an image. The accepted formats are binary file, base64 data, or a URL of the image. Anyone know where we can get an image?

Looking closer at the NASA response object from our first request, we can once again parse the JSON object to retrieve and store our data, like the URL for our image.

  • Set environment variables: Under the Tests tab of our first request to NASA, within the same code block that we parsed our response from NASA, use Postman’s setEnvironmentVariable() method and pass in our key and value. Save your updates.

  • Use environment variables: Under the Body tab of our last Imgur request, add parameter values using double curly braces to access our environment variables. And if you haven’t already, save this third request to your collection.


Run a collection

We now have 3 requests in our collection. The first request returns a response object from NASA.  The second request gets an auth token from Imgur. The third request uses stored values from the first two requests to post the image to Imgur. We’ve chained together subsequent requests using environment variables, and now we can execute our requests by running the collection in its entirety.

1. Click on the right angle bracket (>) next to the collection to open the collection details flyout, and click the blue Run button to open the collection runner in a separate window.

2. Verify that the correct collection and environment is selected in the dropdowns, and then click the Start Run button.

In the collection runner, watch your tests running (and hopefully passing). If all goes well, your picture has been posted privately to Imgur under your Imgur account.

Using the collection runner is just one way to run a collection.  You can also automate your collection runs using custom scripts with Newman or scheduling monitors.


Share a collection

Say your grandma wants to run your collection. How can you share the collection with her?

1. Make sure you're signed in to your Postman account, and click on the right angle bracket (>) next to the collection again, and click the orange Share button to open the SHARE COLLECTION modal.

2. Under the Collection Link tab, get a shareable link. This link represents a snapshot of your collection at the time of generating the link.  If you make changes to the collection later on, you can update the link to sync the changes. 

Using a collection link is just one way to share a collection.  Here comes another one.  Download the collection and environment using the Run in Postman button:

Run in Postman


Quickstart – check it out for yourself

Click the Run in Postman button to import this sample collection and environment into the Postman app. Check out the detailed documentation for this collection and follow along with related screenshots.

1. Register your Imgur app: Head to Imgur and register a new application. Select OAuth 2 authorization with a callback URL, and add the following Authorization callback URL – https://www.getpostman.com/oauth2/callback. Make a note of your Client ID and Client secret for the next step.

2. Update your Imgur credentials in Postman: In the Postman app, head to the Quick Look icon in the top right to view your variables, and click the Edit link. Update the imgurClientId and imgurClientSecret values.

3. Get an auth token from Imgur: In the Postman app, under a new request (separate from the example collection), click on the Authorization tab, select OAuth 2.0, click on the Get New Access Token button, and fill in these values:

Click on Request Token to initiate the OAuth 2.0 flow authorizing the Postman app to connect to your Imgur account. Add the refresh_token value to your environment under the imgurRefreshToken key.

4. Run the collection: Click on the right angle bracket (>) next to the collection to open the collection details flyout, and click the blue Run button. Verify the correct collection and environment is selected in the respective dropdowns, and then click the Start Run button.

If all goes well, your picture has been posted privately under your Imgur account. For extra credit, try creating an album, maybe adding yet another request for some cat tax, and sharing the album with the Imgur community for all the internet karma you can handle.

Read the whole story
alvinashcraft
2 hours ago
reply
West Grove, PA
Share this story
Delete

Go Beyond Username/Password with Modern Authentication

1 Share
Learn how to leave usernames and passwords behind with social and passwordless authentication.
Read the whole story
alvinashcraft
2 hours ago
reply
West Grove, PA
Share this story
Delete

Stable Release: 15.2.2 Xamarin.Android, Xamarin.VS Hotfix

1 Share

We are releasing a service release for Xamarin.Android and Xamarin.VS as part of our current major release, called 15.2, into the Alpha, Beta, and Stable channels to address this critical bug.

This service release is not yet available in Visual Studio 2017. The Xamarin changes have been integrated into the upstream Visual Studio 2017 packaging process, but the service release for the full Visual Studio 2017 is still being finalized, unrelated to the Xamarin changes in particular. The Xamarin packages for Mac and Visual Studio 2015 are being published today to provide the earliest availability of the fixes for those environments.

If you notice an error in this blog post or have trouble downloading one of the installer packages, please let us know in the corresponding forum thread.


Updating from Xamarin Studio to Visual Studio for Mac

Visual Studio for Mac is now generally available as announced at the Microsoft Build conference. It is the recommended environment for Xamarin developers on Mac moving forward. To get started with Visual Studio on Mac, download and run the Visual Studio for Mac installer. It will install Visual Studio for Mac as a new app alongside Xamarin Studio.


Products Released


Installing

You can get this latest version by checking for updates on the Stable updater channel.


Upcoming Release Dates

Stable – May 10th 2017

Stable 2 – May 23rd 2017

Stable 3 – This Release!

Read the whole story
alvinashcraft
2 hours ago
reply
West Grove, PA
Share this story
Delete

What First-Party Kotlin Support Means for Your Business

1 Share

Last week, Google announced official support for the Kotlin programming language on Android. Now, developers can write their apps in either Java or Kotlin.

Developers are excited about this news, but what does it mean for business owners? Is this a positive change—or a burden?

First things first: Kotlin is optional, and you can continue developing your Android app in Java, just as you always have. So why would you switch to Kotlin? We think there are a number of benefits.

Less Code and Built-In Conveniences

Kotlin is a modern language that was created to improve some of the pain points that developers have learned over the many, many years of using Java and other languages.

This means that the language has many conveniences built in. Something that used to require hundreds of lines of code may now require just a few lines in Kotlin. Not all updates will be as drastic, but Kotlin does often allow you to do the same thing that you are currently doing in Java, but with less code.

And the less code your developers have to write, the better. Additional code takes more time to write, has a higher chance of bugs and requires more time to manage in the long run. In essence, Kotlin means less code and less code means fewer problems.

Fewer Bugs

Kotlin helps reduce bugs in your code because it forces the developer to make certain decisions about their code as they write it.

In Java, many of these decisions are implicit, or default to the most permissive option. This means that those decisions are often an afterthought. Delaying these decisions can lead to crashes in your app—and you find out only after your app is in the hands of your users as they begin experimenting with it.

In contrast, Kotlin allows you to discover some of these issues as soon as the code is written. You will find and fix these kinds of issues before they end up affecting your users, ultimately leading to a better user experience, higher Play Store reviews and more downloads.

Kotlin and Your Existing Code

Kotlin works with Java, but it was designed to improve the experience developers have when writing their code. Because of its flexibility, you can start by converting a single file to the Kotlin language mid-project without having to rewrite the old Java code, meaning that you don’t have to switch everything over, at least not immediately.

That being said, the transition to Kotlin should be fairly easy for developers since it is a comfortable transition for people who already know Java. And once the language is learned, it’s bound to save time and headaches, ultimately freeing developers to improve current projects, create additional projects and experiment with the ever-growing Internet of Things across Google’s array of platforms.

The Future

Google values developer feedback; official support for Kotlin is here because the community demanded it. Android developers at prominent companies like Basecamp and Pinterest have already switched over to Kotlin and have seen benefits in their projects. As more and more companies make the leap, you can expect to see Google (and the entire Android community) continue to promote Kotlin and place less emphasis on Java.

All of this means that now is the time to plan for Kotlin. While Google is unlikely to completely drop support for Java in the near future, Kotlin is here and will quickly become the preferred language going forward.

Ready to get started with the transition? We’ve been writing code in Kotlin for years, and we have the expertise to help your team embrace this change. If you’d like to learn more about Kotlin, contact our sales team for more information on how we can help you move your business forward into this new era of Android development.

Read the whole story
alvinashcraft
2 hours ago
reply
West Grove, PA
Share this story
Delete

Care and Feeding of Your New Junior Dev

1 Share

On this episode of Eat Sleep Code, Mike Hand shares strategies for training and mentoring as well as some common and some less obvious pitfalls. When and how to give feedback are covered. In addition, Mike shares advice on using code reviews and pair programming to your advantage, and how to be the experienced developer juniors think you are, with the focus on practical dos and don’ts you can start using right away.

Mike Hand

Mike has been in software development for over 10 years, working everywhere from top 10 defense contractors, small privately owned companies, freelance, and the world of consulting.

Show Notes

Care and Feeding of Your New Junior Dev

The post Care and Feeding of Your New Junior Dev appeared first on Telerik Developer Network.

Read the whole story
alvinashcraft
3 hours ago
reply
West Grove, PA
Share this story
Delete
Next Page of Stories