Skip to content

mitch-b/adaptivecardmaker-dotnet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AdaptiveCardMaker

Nuget install nuget build

Package to help simplify templating language/generation of Adaptive Cards from .NET.

See:

Getting Started

Add package to your project:

dotnet add package AdaptiveCardMaker

This library will pull JSON files as embedded resources from your assembly manifest.

In your .csproj, ensure your JSON files are listed as an embedded resource.

  <ItemGroup>
    <EmbeddedResource Include="Cards\welcomeCard.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </EmbeddedResource>
  </ItemGroup>

This can also be verified in Visual Studio by looking at Properties pane and ensuring the following is true:

Property Value
Build Action Embedded resource
Copy to Output Directory Copy if newer (or always)

Usage

If you do not need to pull resources across multiple assemblies, follow Simple guidance. Otherwise, check out the Advanced section below.

Simple

The simple instructions assume your Adaptive Card JSON files are configured to be embedded resources within your primary executing project (not from a shared library). For example, if your application is a Web app (like it would for a Bot Framework app), the assumption is you would have your cards in a folder named Cards directly in your web app project.

Then, in your service registration (typically Startup.cs), add this library:

namespace Sample.Bot
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAdaptiveCardGenerator();
            // ...
        }
        // ...
    }
}

Now, you can start using the CardGenerator from your Dialog/other classes. For a sample card, named welcomeCard.json:

{
  "type": "AdaptiveCard",
  "body": [
    {
      "type": "TextBlock",
      "size": "Medium",
      "weight": "Bolder",
      "text": "Hi, ${name}"
    }
  ],
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.2"
}

Here's an example how to create the Adaptive Card Attachment within a Dialog of a Bot Skill:

namespace Sample.Bot.Dialogs
{
    public class WelcomeDialog : SkillDialogBase
    {
        private readonly ICardGenerator _cardGenerator;
        public WelcomeDialog(
            IServiceProvider serviceProvider,
            ICardGenerator cardGenerator)
            : base(nameof(WelcomeDialog), serviceProvider)
        {
            _cardGenerator = cardGenerator;
            // ...
        }

        private async Task<DialogTurnResult> DisplayWelcomeAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var cardData = new
            {
                name = "Jane" // card says "Hi, Jane"
            };
            var responseCard = await this._cardGenerator.CreateAdaptiveCardAttachmentAsync("welcomeCard.json", cardData);
            var response = MessageFactory.Attachment(responseCard);
            await stepContext.Context.SendActivityAsync(response);
            return await stepContext.NextAsync(cancellationToken: cancellationToken);
        }
        // ...
    }
}

To override defaults:

services.AddAdaptiveCardGenerator(options =>
{
    // folder containing JSON files from root of project
    options.RelativeOrderedPathToCards = new[] { "Cards" };
});

See the Test projects for examples.

Advanced

If your JSON assets are served by a referenced project (not same assembly as your web bot, for example), you will want to ensure you can pass the Assembly via reflection to the service registration. It supports a generic type in registration so you can register as many instances of the AdaptiveCardMaker as you need.

In this example, say the referenced library (TestCardConsumer.CardLibrary) containing embedded resources had a simple class we can reference:

namespace TestCardConsumer.CardLibrary
{
    // can be completely empty, just used with reflection to get Assembly by type
    public class ImportedCardLibrary
    {
    }
}

Then, in our service registration, we use the typed service registration method:

services.AddAdaptiveCardGenerator<ImportedCardLibrary>(options =>
{
    options.AssemblyWithEmbeddedResources = Assembly.GetAssembly(typeof(ImportedCardLibrary));
    options.RelativeOrderedPathToCards = new[] { "MyCards" };
});

Then when you need this service injected, use the typed interface:

// ...
namespace Sample.Bot.Dialogs
{
    public class WelcomeDialog : SkillDialogBase
    {
        private readonly ICardGenerator<ImportedCardLibrary> _cardGenerator;
        public WelcomeDialog(
            IServiceProvider serviceProvider,
            ICardGenerator<ImportedCardLibrary> cardGenerator)
            : base(nameof(WelcomeDialog), serviceProvider)
        {
            _cardGenerator = cardGenerator;
            // ...
        }

        private async Task<DialogTurnResult> DisplayWelcomeAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var cardData = new
            {
                name = "Jane" // card says "Hi, Jane"
            };
            var responseCard = await this._cardGenerator.CreateAdaptiveCardAttachmentAsync("welcomeCard.json", cardData);
            var response = MessageFactory.Attachment(responseCard);
            await stepContext.Context.SendActivityAsync(response);
            return await stepContext.NextAsync(cancellationToken: cancellationToken);
        }
        // ...
    }
}

About

Helper utility for AdaptiveCards

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages