Exercise – Create a new Retail Server extension
Retail Server extensions are used as services to expose the logic from Commerce runtime. To create a Retail Server extension, follow these steps:
- Create the CRT extension before you create the Retail Server extension. A Retail Server API should have no logic except that which calls the CRT with the parameters.
- Create a new C# class library project that uses Microsoft .NET Framework version 4.6.1, or use any of the Retail Server samples in the Commerce SDK as a template.
- In the Retail Server extension project, add a reference to your CRT extension library or project. This reference lets you call the CRT request, response, and entities.
- In the Retail Server extension project, add the Microsoft.Dynamics.Commerce.Hosting.Contracts package by using the NuGet package manager. NuGet packages can be found in the RetailSDK\pkgs folder.
- Create a new controller class and then extend it from IController. This controller class contains the method that must be exposed by the Retail Server API. Inside the controller class, add methods to call the CRT request. Don’t extend the new controller class from existing controller classes such as CustomerController and ProductController. Extension classes must extend the IController class only.
- Add the RoutePrefix attribute on the controller class to bind it to an entity. If it’s not bound to an entity, this attribute is not required. The BindEntity attribute is required on a controller class if you’re creating a new controller and exposing an entity.
The following sample code creates a simple Retail Server API to return an entity, a string, and a bool value. The CRT request and response that is used in the sample is not included in this sample. For an example of the CRT request and response, see Commerce runtime (CRT) extensibility and triggers.Copy
```csharp
/// <summary>
/// New extended controller.
/// </summary>
[RoutePrefix("SimpleExtension")]
[BindEntity(typeof(SimpleEntity))]
public class SimpleExtensionController : IController
{
/// <summary>
/// The action to get the string value.
/// </summary>
/// <param name="context">The context parameters.</param>
/// <param name="stringValue">The string value parameters.</param>
/// <returns>The string value.</returns>
[HttpPost]
[Authorization(CommerceRoles.Customer, CommerceRoles.Employee)]
public async Task<string> GetStringValue(IEndpointContext context, string stringValue)
{
GetStringValueResponse resp = await context.ExecuteAsync<GetStringValueResponse>
(new GetStringValueRequest(stringValue)).ConfigureAwait(false);
return resp.StringValue;
}
/// <summary>
/// The action to get the bool value.
/// </summary>
/// <param name="context">The context parameters.</param>
/// <param name="boolValue">The string value parameters.</param>
/// <returns>The bool value.</returns>
[HttpPost]
[Authorization(CommerceRoles.Customer, CommerceRoles.Employee)]
public async Task<bool> GetBoolValue(IEndpointContext context, string boolValue)
{
GetBoolValueResponse resp = await context.ExecuteAsync<GetBoolValueResponse>
(new GetBoolValueRequest(boolValue)).ConfigureAwait(false);
return resp.BoolValue;
}
/// <summary>
/// The action to get the simple entity.
/// </summary>
/// <param name="context">The context parameters.</param>
/// <param name="name">The name parameters.</param>
/// <returns>The simple entity.</returns>
[HttpPost]
[Authorization(CommerceRoles.Customer, CommerceRoles.Employee)]
public async Task<SimpleEntity> GetSimpleEntity(IEndpointContext context, string name)
{
GetSimpleEntityResponse resp = await context.ExecuteAsync<GetSimpleEntityResponse>
(new GetSimpleEntityRequest(name)).ConfigureAwait(false);
return resp.SimpleEntityObj;
}
```
- Build the extension project and copy the binary to the \RetailServer\webroot\bin\Ext folder.
- Update the Commerce Scale Unit web.config file in the \RetailServer\webroot folder by adding the new extension library name in the extensionComposition section.C#Copy
<extensionComposition> <!-- Use fully qualified assembly names for ALL if you need to support loading from the Global Assembly Cache. If you host in an application with a bin folder, this is not required. --> <add source="assembly" value="SimpleExtensionSample" > </extensionComposition>
- In Microsoft Internet Information Services (IIS), restart the Commerce Scale Unit to load the new extension.
- To verify that the extension loaded successfully, you can browse the Retail Server metadata. Confirm that your entities and methods appear in the list. To browse the metadata, open a URL in the following format in a web browser: https://RS-URL/Commerce/$metadata
- To call the Retail Server extension in your client, you must generate the client TypeScript proxy. You can then use the proxy to call your new Retail Server APIs from the client. You don’t need to add or include EdmModelExtender files in the extension with the Retail Server extension APIs. The files are required only if you’re using Commerce SDK version 10.0.10 or earlier. A Retail Server extension that is built by using this new Microsoft.Dynamics.Commerce.Hosting.Contracts API can be used in an offline implementation. You don’t need to generate a separate C# proxy library. Copy the Retail Server extension library in the \Microsoft Dynamics 365\70\Retail Modern POS\ClientBroker\ext folder and then update the RetailProxy.MPOSOffline.ext config file to include this new library. The extension must generate the TypeScript proxy only. SDK samples can be found in the \RetailSDK\SampleExtensions\TypeScriptProxy folder. The following example shows how to update the add element in the RetailProxy.MPOSOffline.ext config file.C#Copy
<?xml version="1.0" encoding="utf-8"?> <retailProxyExtensions> <composition> <add source="assembly" value="Contoso.RetailServer.StoreHoursSample" /> </composition> </retailProxyExtensions>