From 2697f512e9dd3dd9ac75a8208a6e23ceb19c7640 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Tue, 24 Jan 2023 22:39:31 +0100 Subject: [PATCH] Implement XML content writer --- .../Elsa.Http/Activities/WriteHttpResponse.cs | 7 ++--- .../ContentWriters/JsonContentFactory.cs | 4 +-- .../ContentWriters/TextContentFactory.cs | 3 +- .../ContentWriters/XmlContentFactory.cs | 31 +++++++++++++++++++ src/modules/Elsa.Http/Features/HttpFeature.cs | 10 ++++-- .../Elsa.Http/Options/HttpActivityOptions.cs | 18 +++++++++++ ...eHttpResponseContentTypeOptionsProvider.cs | 18 +++++++++++ .../RunJavaScriptOptionsProvider.cs | 2 +- .../IActivityPropertyOptionsProvider.cs | 8 ++++- 9 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 src/modules/Elsa.Http/ContentWriters/XmlContentFactory.cs create mode 100644 src/modules/Elsa.Http/Providers/WriteHttpResponseContentTypeOptionsProvider.cs diff --git a/src/modules/Elsa.Http/Activities/WriteHttpResponse.cs b/src/modules/Elsa.Http/Activities/WriteHttpResponse.cs index 00416271b..bc9ddbda7 100644 --- a/src/modules/Elsa.Http/Activities/WriteHttpResponse.cs +++ b/src/modules/Elsa.Http/Activities/WriteHttpResponse.cs @@ -1,13 +1,12 @@ using System.Net; -using System.Net.Http.Headers; using Elsa.Extensions; using Elsa.Http.ContentWriters; +using Elsa.Http.Models; +using Elsa.Http.Providers; using Elsa.Workflows.Core.Attributes; using Elsa.Workflows.Core.Models; using Elsa.Workflows.Management.Models; using Microsoft.AspNetCore.Http; -using HttpRequestHeaders = Elsa.Http.Models.HttpRequestHeaders; -using HttpResponseHeaders = Elsa.Http.Models.HttpResponseHeaders; namespace Elsa.Http; @@ -34,7 +33,7 @@ public class WriteHttpResponse : CodeActivity /// [Input( Description = "The content type to use when returning the response.", - Options = new[] { "", "text/plain", "text/html", "application/json", "application/xml", "application/x-www-form-urlencoded" }, + OptionsProvider = typeof(WriteHttpResponseContentTypeOptionsProvider), UIHint = InputUIHints.Dropdown )] public Input ContentType { get; set; } = default!; diff --git a/src/modules/Elsa.Http/ContentWriters/JsonContentFactory.cs b/src/modules/Elsa.Http/ContentWriters/JsonContentFactory.cs index 401443f18..f5fcb53ae 100644 --- a/src/modules/Elsa.Http/ContentWriters/JsonContentFactory.cs +++ b/src/modules/Elsa.Http/ContentWriters/JsonContentFactory.cs @@ -6,11 +6,11 @@ using System.Text; namespace Elsa.Http.ContentWriters; /// -/// Creates a object for application/json. +/// Creates a object for application/json. /// public class JsonContentFactory : IHttpContentFactory { - private readonly List _supportedContentTypes = new() { MediaTypeNames.Application.Json }; + private readonly List _supportedContentTypes = new() { MediaTypeNames.Application.Json, "text/json" }; /// public bool SupportsContentType(string contentType) => _supportedContentTypes.Contains(contentType); diff --git a/src/modules/Elsa.Http/ContentWriters/TextContentFactory.cs b/src/modules/Elsa.Http/ContentWriters/TextContentFactory.cs index 197488480..b70c3f231 100644 --- a/src/modules/Elsa.Http/ContentWriters/TextContentFactory.cs +++ b/src/modules/Elsa.Http/ContentWriters/TextContentFactory.cs @@ -4,14 +4,13 @@ using System.Text; namespace Elsa.Http.ContentWriters; /// -/// Creates a object for application/json, application/xml, text/json and text/xml content types. +/// Creates a object for text/plain, text/richtext and text/html content types. /// public class TextContentFactory : IHttpContentFactory { private readonly List _supportedContentTypes = new() { MediaTypeNames.Text.Plain, - MediaTypeNames.Text.Xml, MediaTypeNames.Text.RichText, MediaTypeNames.Text.Html, }; diff --git a/src/modules/Elsa.Http/ContentWriters/XmlContentFactory.cs b/src/modules/Elsa.Http/ContentWriters/XmlContentFactory.cs new file mode 100644 index 000000000..d8a23309d --- /dev/null +++ b/src/modules/Elsa.Http/ContentWriters/XmlContentFactory.cs @@ -0,0 +1,31 @@ +using System.Net.Http.Headers; +using System.Net.Mime; +using System.Text; +using System.Xml.Serialization; + +namespace Elsa.Http.ContentWriters; + +/// +/// Creates a object for application/json. +/// +public class XmlContentFactory : IHttpContentFactory +{ + private readonly List _supportedContentTypes = new() { MediaTypeNames.Application.Xml, MediaTypeNames.Text.Xml }; + + /// + public bool SupportsContentType(string contentType) => _supportedContentTypes.Contains(contentType); + + /// + public HttpContent CreateHttpContent(object content, string contentType) + { + var text = content as string ?? Serialize(content); + return new StringContent(text, Encoding.UTF8, contentType); + } + + private string Serialize(object value) + { + using var writer = new StringWriter(); + new XmlSerializer(value.GetType()).Serialize(writer, value); + return writer.ToString(); + } +} \ No newline at end of file diff --git a/src/modules/Elsa.Http/Features/HttpFeature.cs b/src/modules/Elsa.Http/Features/HttpFeature.cs index 6073e974c..bd1ec4c0c 100644 --- a/src/modules/Elsa.Http/Features/HttpFeature.cs +++ b/src/modules/Elsa.Http/Features/HttpFeature.cs @@ -8,7 +8,9 @@ using Elsa.Http.Handlers; using Elsa.Http.Implementations; using Elsa.Http.Options; using Elsa.Http.Parsers; +using Elsa.Http.Providers; using Elsa.Http.Services; +using Elsa.Workflows.Management.Implementations; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; @@ -78,15 +80,19 @@ public class HttpFeature : FeatureBase .AddNotificationHandlersFrom() .AddHttpContextAccessor() - // Add content parsers. + // Content parsers. .AddSingleton() .AddSingleton() .AddSingleton() - // Add HTTP content factories. + // HTTP content factories. .AddSingleton() .AddSingleton() + .AddSingleton() .AddSingleton() + + // Activity property options providers + .AddSingleton() ; } } \ No newline at end of file diff --git a/src/modules/Elsa.Http/Options/HttpActivityOptions.cs b/src/modules/Elsa.Http/Options/HttpActivityOptions.cs index c9dea4486..2894059dc 100644 --- a/src/modules/Elsa.Http/Options/HttpActivityOptions.cs +++ b/src/modules/Elsa.Http/Options/HttpActivityOptions.cs @@ -2,6 +2,9 @@ using Microsoft.AspNetCore.Http; namespace Elsa.Http.Options; +/// +/// Provides various options related to the HTTP activities. +/// public class HttpActivityOptions { /// @@ -13,4 +16,19 @@ public class HttpActivityOptions /// The base URL of the server. This should be set to the same value at which the Elsa Server is publicly available. It will be used when generating absolute URLs need to be generated by activities such as SendEmail. /// public Uri BaseUrl { get; set; } = default!; + + /// + /// A configurable set of available content types available from the activity. + /// + public ISet AvailableContentTypes { get; set; } = new HashSet + { + "application/json", + "application/xml", + "application/x-www-form-urlencoded", + "application/octet-stream", + "text/plain", + "text/html", + "text/json", + "text/xml", + }; } \ No newline at end of file diff --git a/src/modules/Elsa.Http/Providers/WriteHttpResponseContentTypeOptionsProvider.cs b/src/modules/Elsa.Http/Providers/WriteHttpResponseContentTypeOptionsProvider.cs new file mode 100644 index 000000000..f280cd49d --- /dev/null +++ b/src/modules/Elsa.Http/Providers/WriteHttpResponseContentTypeOptionsProvider.cs @@ -0,0 +1,18 @@ +using System.Reflection; +using Elsa.Http.Options; +using Elsa.Workflows.Management.Implementations; +using Microsoft.Extensions.Options; + +namespace Elsa.Http.Providers; + +internal class WriteHttpResponseContentTypeOptionsProvider : IActivityPropertyOptionsProvider +{ + private readonly HttpActivityOptions _options; + + public WriteHttpResponseContentTypeOptionsProvider(IOptions options) + { + _options = options.Value; + } + + public object GetOptions(PropertyInfo property) => new[] { "" }.Concat(_options.AvailableContentTypes); +} \ No newline at end of file diff --git a/src/modules/Elsa.JavaScript/Activities/RunJavaScriptOptionsProvider.cs b/src/modules/Elsa.JavaScript/Activities/RunJavaScriptOptionsProvider.cs index 00b094f2d..f8f714162 100644 --- a/src/modules/Elsa.JavaScript/Activities/RunJavaScriptOptionsProvider.cs +++ b/src/modules/Elsa.JavaScript/Activities/RunJavaScriptOptionsProvider.cs @@ -6,7 +6,7 @@ namespace Elsa.JavaScript.Activities; internal class RunJavaScriptOptionsProvider : IActivityPropertyOptionsProvider { - public object? GetOptions(PropertyInfo property) + public object GetOptions(PropertyInfo property) { return new CodeEditorOptions { diff --git a/src/modules/Elsa.Workflows.Management/Implementations/IActivityPropertyOptionsProvider.cs b/src/modules/Elsa.Workflows.Management/Implementations/IActivityPropertyOptionsProvider.cs index 225625c09..543187335 100644 --- a/src/modules/Elsa.Workflows.Management/Implementations/IActivityPropertyOptionsProvider.cs +++ b/src/modules/Elsa.Workflows.Management/Implementations/IActivityPropertyOptionsProvider.cs @@ -2,7 +2,13 @@ using System.Reflection; namespace Elsa.Workflows.Management.Implementations; +/// +/// Provides options about a given activity property. +/// public interface IActivityPropertyOptionsProvider { - object? GetOptions(PropertyInfo property); + /// + /// Returns options for the specified property. + /// + object GetOptions(PropertyInfo property); } \ No newline at end of file