Build an ASP.NET Core Web App with Adoxio Connect Framework

Microsoft’s ASP.NET team is going through a big transition period right now to an open source redesign of ASP.NET called ASP.NET Core. ASP.NET Core has major changes that are meant to try to make it more accessible to a larger set of developers as well as bringing it to many platforms with incredible performance improvements. If you’re a web developer building ASP.NET sites that connect to Dynamics 365 this will be an important platform to investigate and use in your solutions. In this post we will walk through a sample of a Dynamics 365 Web App that is built on ASP.NET Core and use the Server-to-Server authentication that Adoxio Connect Framework provides.

Previously we have built samples for a Console Application and a standard ASP.NET Web Application. What makes ASP.NET Core different is that is all the new versions of MVC, Web Api, OWIN and the entire framework being built on .NET Standard instead of the .NET Framework. The change of building ASP.NET Core by following .NET Standard is the single largest change and is what makes the framework now cross platform and able to run on Linux. As Dynamics developers we need to continue using the .NET Framework due to the dependencies the Dynamics 365 SDK has to use .NET Framework components. It is not unexpected though, removing .NET Framework is big change and will take considerable time to make a shift (v8.2 shows approximately 75% compatibility with .NET Standard). This however does not mean they we can’t use ASP.NET Core as Dynamics developers because ASP.NET Core can also be run on .Net Framework since it is .NET Standard compatible. This means you can use .NET Framework based libraries like the Dynamics 365 SDK or others like SharePoint, and even Adoxio Connect Framework.

So Why Use ASP.NET Core
Their are huge changes that are great for developers and builders to make use of. There are major benefits in terms of modularization of the request pipeline, dependency injection a core part of the platform, performance (a factor of 10 compared to ASP.NET 4.6), new MVC version, and open source! If you’re build a brand new web app then you should strong consider starting with ASP.NET Core.

As such let’s look at how you can use Adoxio Connect Framework with this version and understand some of the differences from the ASP.NET implementation.


Firstly let’s start by creating a new ASP.NET Core project. You can do this with the latest version of Visual Studio, 2017. Select from the ASP.NET Core Web Application (.NET Framework) template under Visual C# > Web area. It’s important you select the .NET Framework version so we can support the Dynamics 365 SDK, and select .NET Framework 4.6.1 which Adoxio Connect Framework requires.

Next select Web Application while ensuring that ASP.NET Core 1.1 is selected in the version drop down.

With the new web project just like the standard ASP.NET sample we want to include the necessary NuGet packages necessary to connect to Dynamics 365. As we are going to use a Server-to-Server based authentication we are going to use Adoxio Connect Framework to make that implementation easy in the application. Within the project, right click Dependencies in the Solution Explorer and select Manage NuGet Packages… Within the NuGet package manager, select Browse and search for “Adoxio”, then select and install the latest version of Adoxio.Dynamics.Connect.

Adoxio Connect Framework will also bring in the necessary dependencies when it installs including the Dynamics 365 SDK.

This is the only package to install with ASP.NET Core to get started, making it super simple to start. Now with all the dependencies installed to the project the next step is to ensure you have done the necessary setup for server-to-server authentication. This includes creating an Azure AD application with the appropriate API access, and creating an application user with a security role in CRM. To learn more about the server-to-server authentication setup follow the MSDN documentation. Follow the same steps for multi-tenant for building this single tenant web application, other than you don’t need to worry about creating a process to deploy the application user as it will be a one time process per Dynamics instance. Use Multi-Tenant Server-to-server authentication

Once your have your S2S settings created (you will need a Client Id, Client Secret, the instance or resource – your Dynamics instance URL, and Azure AD tenant ID) then we need to input them into the ASP.NET Core app settings. This differs from the standard ASP.NET application as that configuration was all XML based and heavily used the Configuration Manager. Both in ASP.NET Core are no more. Settings are now stored in JSON and are retrieved via dependency injection in the OWIN App Startup services configuration. First let’s put a structure to read in the appsettings.json file.


  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AdoxioConnect": {
    "dynS2S": {
      "ClientId": "1d8925fd-8cbe-4f07-a83f-f59f7b111350",
      "ClientSecret": "ckrtN4TrckIAF1i5ccEcJw+C4/ESfcyjWGBRBI80a3A=",
      "Resource": "https://connectexampleinstance.crm.dynamics.com",
      "TenantId": "ae83bd39-7849-4089-3965-1e5749dc4dc2"
    }
  }
}

These are just sample values.

With the settings now input we need to have the ASP.NET Core application add them to its dependency injection pipeline so we can then use them when forming the CrmContext constructor so we have a context to communicate with Dynamics 365.

Open the Startup.cs class and navigate to the ConfigureServices method. In this method we are going to use the S2SAppSettings class that comes with Adoxio Connect Framework to register the settings in the appsettings.json as an object that can be accessed in the application.

services.Configure<S2SAppSettings>(Configuration.GetSection("AdoxioConnect:dynS2S"));

We can use S2SAppSettings because the names we used in the appsettings.json match that class definition. This class object will now be available to the entire application through the platform based dependency injection. You can read more about the DI in ASP.NET Core here – Introduction to Dependency Injection in ASP.NET Core

With the settings now available we need to make a small extension class to support the DI in ASP.NET Core in Adoxio Connect Framework. Create a new folder called Extensions if you want, and then a new class which you can call CrmContextCore.cs. In this class we simply just want to add a new constructor to the CrmContext that is part of Adoxio Connect Framework which will allow it to read the S2SAppSettings through the dependency injection.

using Adoxio.Dynamics.Connect;
using Microsoft.Extensions.Options;

namespace Adoxio.Connect.WebCore.Extensions
{
    public class CrmContextCore : CrmContext
    {
        public CrmContextCore(IOptions<S2SAppSettings> s2sAppSettingsOptions) : base(s2sAppSettingsOptions.Value)
        {
        }
    }
}

Why didn’t we just add this to Adoxio Connect? It would require making a library for both ASP.NET Core and standard ASP.NET because of the IOptions dependency so we decided this was such a small simple change as well as a place to start building extensions to the framework in your own project that we would stick with a single library until there were more benefits.

All that is in this class is firstly it inherits and extends the CrmContext class and add a new constructor that reads the S2SAppSettings as an IOptions object that then calls the base constructor with the value of the S2SAppSettings object. If you wanted to use the Xrm Tooling, CrmServiceClient this would be a good class to make those changes as well. This CrmContextCore class is what we will next be adding to the ASP.NET Core application as a singleton so that it is also available to the whole application through dependency injection.

Back in Startup.cs under the ConfigureServices method we can now add our new class as that singleton object.

services.AddSingleton<CrmContextCore>();

Why AddSingleton? You can read more about the different service types for adding objects to the pipeline here with Service Lifetimes and Registration Options, as well there is a good answer on StackOverflow depicting an example of all of them. The reason here is that we really only need 1 connection to the Dynamics 365 instance in the entire application and there is no need to recreate the object on every request. So with a singleton we get a single object created at the startup of the application which makes for great performance on every request.

The ConfigureServices method should now have 2 additional lines as below and that is all the configuration that is actually needed to use the Adoxio Connect Framework and have a context that will allow you to interact with the Dynamics 365 instance through that Server-to-Server connection.

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    services.Configure<S2SAppSettings>(Configuration.GetSection("AdoxioConnect:dynS2S"));
    services.AddSingleton<CrmContextCore>();
}

Now that the application is setup we can now start creating controllers and other functions in the application that can access these objects easily through the dependency injection. Let’s look at a simple controller that implements some simple SDK calls.

using Microsoft.AspNetCore.Mvc;
using WebApplication13.Extensions;

namespace WebApplication13.Controllers
{
    public class CrmSdkController : Controller
    {
        private readonly CrmContextCore _crmContext;

        public CrmSdkController(CrmContextCore crmContext)
        {
            _crmContext = crmContext;
        }

        public IActionResult Index()
        {
            return View();
        }
    }
}

The addition we make to our class to make use of our context is just simply adding a constructor to the class that calls to singleton object we added to the application and then stores it in a private object that is accessible throughout the class. ASP.NET Core’s dependency injection makes it all this easy.

Now you can build methods that use the context to call Dynamics 365 using your normal SDK calls. Below is the same method as both a MVC view and an API JSON return within the exact same controller which is all now combined in ASP.NET Core MVC.

public IActionResult Index()
{
    var contacts = _crmContext.ServiceContext.CreateQuery("contact").ToList();
    return View(model: string.Join(",", contacts.Select(a => a.GetAttributeValue<string>("fullname"))));
}

[Produces("application/json")]
[Route("api/CrmSdk")]
public IEnumerable<Entity> GetContacts()
{
    var contacts = _crmContext.ServiceContext.CreateQuery("contact").ToList();
    return contacts;
}

All of this new ASP.NET Core sample code is now part of the samples on the Adoxio Connect Framework GitHub repo.

Again if your starting a new web development project for Dynamics 365 definitely consider ASP.NET Core even though your still using .NET Framework. There is still significant benefit to mixing the 2 together.

If your interested to know more about the Adoxio Connect Framework and Dynamics 365 Server-to-Server authentication I will be giving a webinar with the Xrm Virtual User Group this Tuesday July 11th at 12pm EST / 9am PST.

WEBINAR: Wondering what to do with your Adxstudio Portal?

Things are changing in the world of portals for Dynamics 365 or Dynamics CRM. The platform is advancing forward at a rapid pace with new portal options from Microsoft being released and older legacy versions needing to be evaluated for their longevity.

I am often asked to help organizations understand and select the option that is right for them as existing Adxstudio customers looking to be properly supported in the future, or new customers considering what Microsoft portal options are available to them. To help make this content available for everyone I will be giving a webinar with Adoxio Business Solutions on Tuesday, June 27th at 10:00am PST / 11:00am MST / 1:00pm EST.

I invite anyone interested in portals for Dynamics 365 to join. If you already have burning questions you would like answered I would be more than happy to try and answer them during the webinar. Please see the full invitation from Adoxio below and a link to register as well as submit your question prior to the webinar.

Register Now Submit a Question


Join Adoxio on Tuesday, June 27th at 11:00am MST / 1:00pm EST for a webinar that will outline considerations for the future of your Adxstudio Portal. There are a lot of changes in the near future for portals from Microsoft for Dynamics 365. The portal source code will be released, bringing with it another choice for implementations. What does the future potentially hold for the legacy Adxstudio portals? What choices do you have for on-premises deployments?

Get answers to these and more with Colin Vermander, Technical Director for Service Delivery at Adoxio. You will leave understanding what your options are as a current or future portal customer, and get key insights into what Adoxio is recommending.

By attending this webinar, you will learn:

  • Overview of Microsoft’s announcement & their plans to release the code
  • How this will affect you?
  • Solutions and your options moving forward

Dynamics 365 portals: Early Upgrade Option – July 2017 Update

As we near the July 2017 Update for Dynamics 365 it looks like an option for early upgrade has shown up for portal add-ons.

You can find this option on new and existing portal add-ons in the CRM Administration Center under Applications and Manage your Portal Add-On. This option should be used with some caution as it will mean you are in the first release program for portals. What will you get? The next portals release! That release previously was looking to be version 8.3 based on all the information provided at eXtreme365 and the other information available, but it is looking like we might be making the jump to version 9.0 sooner than expected. The roadmap items are still the same as published on roadmap.dynamics.com.

Here is what the new option will look like in the portal add-on management:

Check this box with caution!

Update 6/23/2017: Correction to the versioning, as earlier expected the portals released now will be v8.3 not v9.

Dynamics 365 portals new documentation!

Microsoft Dynamics 365 team has been transitioning all documentation to the new docs.microsoft.com site and just launched now is the new documentation for portals. This is a great change to see and is starting to bring the breadth of documentation in alignment with what is available on the legacy Adxstudio Community site. Having it in the Microsoft docs site will help make the content much more accessible and easier to refer to in blogs, forums and all other ways of sharing :).

The documentation is still a little short on the newest components that are available (no chart liquid object and a couple other items) but I look forward to this being continuously updated as new releases come out. This is only the first release of the documentation and I think we can expect it to be updated regularly.

Dynamics 365 portals: Customize Knowledge Articles

One of the more popular features of the Dynamics 365 portals is its ability to expose the knowledge articles from your internal CRM on the public portal or to select audiences. With how the knowledge article functionality is currently implemented in the portal there is not an easy way to customize the article display or enhance it with more functionality like attachments. However with the customization capability of liquid we can create our own display of an article that includes whatever other data is accessible through liquid. In this post we will look at an example and the other elements like search results that need to be modified to properly support this approach.

Firstly let’s start out by creating our custom article liquid template. To do so create a new Web Template and we are going to assume that an ID parameter will always be passed in the query string so we know what article to surface.

{% assign article = entities.knowledgearticle[request.params.id] %}
<div class="container">
  <div class="page-heading">
      {% include 'Breadcrumbs' title: article.title %}
  <div class="page-header">
   <h1>
     {% if article %}{{article.title}}{% else %}No article found{% endif %}
     <div class="pull-right">
	    <div role="toolbar" class="btn-toolbar">
		    <div class="btn-group">
			    <a href="javascript:window.print()" class="btn btn-default btn-sm"><span class="fa fa-print"></span>&nbsp;{{ snippets['Knowledge Management - Print Button Label'] }}</a>
		    </div>
	    </div>
     </div>
   </h1>
  </div>
 </div>
 <div class="row">
  <div class="col-md-12">
   <div class="page-copy">
     {% if article %}
       {{ article.content }}
     {% endif %}
   </div>
  </div>
 </div>
</div>

This template simply takes the ID parameter, gets the knowledgearticle entity record and then uses the object to display the breadcrumbs using the title parameter in that template. Then displays the page title using the article title and displays a print button just like the default article template. Finally we display the article content attribute which is where the HTML blob is stored if the article is found.

A common enhancement is to add a display of the associated note attachments to the article. With liquid we can easily access the notes and display them in a fashion to provide a list of downloads. You can see the liquid note documentation here. Below is a simple liquid code that will output the notes that are associated to the article displaying the title linked (manually as note.url seems broken or disabled or changed and not documented in v8.x) as well with the note text as the description.

{% assign notes = article.knowledgearticle_annotations %}
{% if notes.size > 0 %}
 <h3>Associated Documents</h3>
 <ul>
   {% for note in notes %}
     <li><p><a href="/_entity/annotation/{{note.id}}">{{note.subject}}</a><br/>{{note.notetext}}</p></li>
   {% endfor %}
 </ul>
{% endif %}

This can be added where you want the list of attachments to display, for this example it is inserted right after the {{article.content}}. This could be further enhanced to conditionally include only this notes that have documents using the attributes of the annotation entity and condition liquid tags. With your web template completed, you should now create a page template and a web page that uses that page template. Once the web page is created, also create a site marker that references the web page as we will use this later to help us link to the new article page.

There are a lot more things you can add to your articles using liquid. You just need to parse through the relationships associated to the article and then present the data appropriately. I may look at some further enhancements in future posts.

With building a custom article template we need to deal with the fact we no longer want the links navigating to the old MVC based article routing. To do so we need to try to replace all the locations that this routing is in place. The largest one is probably the search. With the search being built off handlebars and liquid as we explored in a preview post – Extend Search Results with Handlebars, you can change the default URL for knowledge article results.

First we need to add a handlebars helper in JavaScript to the search results page so we can put in some conditional logic to change the URL when the result is for a knowledgearticle entity record. This is just a simple addition that allows you to do an if equals in handlebars.

Handlebars.registerHelper('if_eq', function(a, b, opts) {
    if(a == b) // Or === depending on your needs
        return opts.fn(this);
    else
        return opts.inverse(this);
});

Now we can make use of this new helper in the Faceted Search – Results Template Web Template. Within the {{#each items}} we are going to modify the contents of the h3 tag to have some conditional logic to change the default link it uses to be our site marker we previously created.

{{#if_eq entityLogicalName "knowledgearticle"}}
  <a title="{{title}}" href="{%endraw%}{{articleSiteMarker.url}}{%raw%}?id={{entityID}}">{{title}}</a>
{{else}}
  <a title="{{title}}" href="{{url}}">{{title}}</a>
{{/if_eq}}

Basically all we have added is a condition that when the result is from a knowledgearticle entity then use our site marker URL passing the entityID as the id as the href of the anchor tag.

Make sure you also at the very top of this web template include a reference to your site marker.

{% assign openTag = '{{' %}
{% assign closingTag = '}}' %}
{% assign articleSiteMarker = sitemarkers["Article"] %}

With the chance of their being some routing that still is hard coded somewhere in the portal we can put some logic on the out of box article default page that will cause it to route to our new page as well. The easiest way to modify this is to login to the portal with an administrative account so you can use the front-side editor to make your changes. Navigate to an existing article you know by using the following route format https://{portal_url}/knowledgebase/article/ka-01000, and replace the ka-01000 with an article code you know exists.

Once on the page then edit using the front-side editor and go to the Options tab. Within the Custom JavaScript section add the following:

var pathArray = window.location.pathname.split( '/' );
var articleCode = pathArray[pathArray.length - 1];
{% assign articleSiteMarker = sitemarkers["Article"] %}
document.location = "{{articleSiteMarker.url}}?code=" + articleCode;

And within the Custom CSS add the following:

body {
  display: none;
}

This will cause a redirect to your new page while hiding the old one during the redirect. We now also need to enhance our custom web template for the article to take the code parameter as well. Replace the assign liquid at the top of the existing template with the following:

{% if request.params.id %}
  {% assign article = entities.knowledgearticle[request.params.id] %}
{% endif %}
{% if request.params.code %}
  {% fetchxml articlefetch %}
    <fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
      <entity name="knowledgearticle">
        <all-attributes /> 
        <filter type="and">
          <condition attribute="islatestversion" operator="eq" value="1" />
          <condition attribute="articlepublicnumber" operator="eq" value="{{request.params.code}}" />
        </filter>
      </entity>
    </fetch>
  {% endfetchxml %}
  {% assign article = articlefetch.results.entities[0] %}
{% endif %}

With all our changes we should now have a custom article page that takes either the entityId or the article code as a parameter, search results routing directly to the new article and a catch for hard coded links to also redirect to the new page template. The same code here will have produced an article with the following format. You of course with liquid templating functionality can continue to customize and enhance this for your requirements.

Note with all these changes we have removed the content access level functionality. You can add this back by developing the appropriate liquid code to make the necessary checks.

Update 6/23/2017: Just announced at the July 2017 Update Executive Briefings, knowledge articles on the portal will be getting an enhancement to expose notes and attachments. This method in this post will still be of interest to those that find that the display is too limiting or there are other components in which they want to include in their knowledge article display.