Merge branch 'v3' into v3-activity-state-tracking-issue
This commit is contained in:
commit
c042429b60
11
.github/workflows/packages.yml
vendored
11
.github/workflows/packages.yml
vendored
|
|
@ -4,6 +4,8 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- v3
|
||||
tags:
|
||||
- preview-*hotfix-* # e.g. preview-1.0.0-hotfix-1
|
||||
release:
|
||||
types: [ prereleased ]
|
||||
env:
|
||||
|
|
@ -23,7 +25,14 @@ jobs:
|
|||
git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/*
|
||||
git branch --remote --contains | grep origin/v3
|
||||
- name: Set VERSION variable
|
||||
run: echo "VERSION=3.0.0-preview.${{github.run_number}}" >> $GITHUB_ENV
|
||||
run: |
|
||||
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
||||
TAG_NAME=${{ github.ref }} # e.g., refs/tags/preview-740-hotfix-1
|
||||
TAG_NAME=${TAG_NAME#refs/tags/} # remove the refs/tags/ prefix
|
||||
echo "VERSION=3.0.0-preview-${TAG_NAME}.${{github.run_number}}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "VERSION=3.0.0-preview.${{github.run_number}}" >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Build designer package
|
||||
working-directory: ./src/modules/Elsa.Workflows.Designer
|
||||
run: |
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Net.Http.Headers;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Http.ActivityOptionProviders;
|
||||
using Elsa.Http.ContentWriters;
|
||||
using Elsa.Workflows.Core;
|
||||
using Elsa.Workflows.Core.Attributes;
|
||||
|
|
@ -18,7 +19,7 @@ public abstract class SendHttpRequestBase : Activity<HttpResponseMessage>
|
|||
protected SendHttpRequestBase(string? source = default, int? line = default) : base(source, line)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The URL to send the request to.
|
||||
/// </summary>
|
||||
|
|
@ -47,7 +48,7 @@ public abstract class SendHttpRequestBase : Activity<HttpResponseMessage>
|
|||
/// </summary>
|
||||
[Input(
|
||||
Description = "The content type to use when sending the request.",
|
||||
Options = new[] { "", "text/plain", "text/html", "application/json", "application/xml", "application/x-www-form-urlencoded" },
|
||||
OptionsProvider = typeof(HttpContentTypeOptionsProvider),
|
||||
UIHint = InputUIHints.Dropdown
|
||||
)]
|
||||
public Input<string?> ContentType { get; set; } = default!;
|
||||
|
|
@ -89,7 +90,7 @@ public abstract class SendHttpRequestBase : Activity<HttpResponseMessage>
|
|||
/// Handles an exception that occurred while sending the request.
|
||||
/// </summary>
|
||||
protected abstract ValueTask HandleRequestExceptionAsync(ActivityExecutionContext context, HttpRequestException exception);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handles <see cref="TaskCanceledException"/> that occurred while sending the request.
|
||||
/// </summary>
|
||||
|
|
@ -111,7 +112,7 @@ public abstract class SendHttpRequestBase : Activity<HttpResponseMessage>
|
|||
|
||||
await HandleResponseAsync(context, response);
|
||||
}
|
||||
catch(HttpRequestException e)
|
||||
catch (HttpRequestException e)
|
||||
{
|
||||
context.AddExecutionLogEntry("Error", e.Message, payload: new { StackTrace = e.StackTrace });
|
||||
context.JournalData.Add("Error", e.Message);
|
||||
|
|
@ -165,14 +166,20 @@ public abstract class SendHttpRequestBase : Activity<HttpResponseMessage>
|
|||
|
||||
if (contentType != null && content != null)
|
||||
{
|
||||
var contentWriters = context.GetServices<IHttpContentFactory>();
|
||||
var contentWriter = SelectContentWriter(contentType, contentWriters);
|
||||
request.Content = contentWriter.CreateHttpContent(content, contentType);
|
||||
var factories = context.GetServices<IHttpContentFactory>();
|
||||
var factory = SelectContentWriter(contentType, factories);
|
||||
request.Content = factory.CreateHttpContent(content, contentType);
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private IHttpContentFactory SelectContentWriter(string? contentType, IEnumerable<IHttpContentFactory> requestContentWriters) =>
|
||||
string.IsNullOrWhiteSpace(contentType) ? new JsonContentFactory() : requestContentWriters.First(w => w.SupportsContentType(contentType));
|
||||
private IHttpContentFactory SelectContentWriter(string? contentType, IEnumerable<IHttpContentFactory> factories)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(contentType))
|
||||
return new JsonContentFactory();
|
||||
|
||||
var parsedContentType = new System.Net.Mime.ContentType(contentType);
|
||||
return factories.FirstOrDefault(httpContentFactory => httpContentFactory.SupportedContentTypes.Any(c => c == parsedContentType.MediaType)) ?? new JsonContentFactory();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
using System.Net;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Http.ActivityOptionProviders;
|
||||
using Elsa.Http.ContentWriters;
|
||||
using Elsa.Http.Models;
|
||||
using Elsa.Http.Providers;
|
||||
using Elsa.Workflows.Core;
|
||||
using Elsa.Workflows.Core.Attributes;
|
||||
using Elsa.Workflows.Core.Exceptions;
|
||||
|
|
@ -40,7 +40,7 @@ public class WriteHttpResponse : Activity
|
|||
/// </summary>
|
||||
[Input(
|
||||
Description = "The content type to write when sending the response.",
|
||||
OptionsProvider = typeof(WriteHttpResponseContentTypeOptionsProvider),
|
||||
OptionsProvider = typeof(HttpContentTypeOptionsProvider),
|
||||
UIHint = InputUIHints.Dropdown
|
||||
)]
|
||||
public Input<string?> ContentType { get; set; } = default!;
|
||||
|
|
@ -105,8 +105,9 @@ public class WriteHttpResponse : Activity
|
|||
if (string.IsNullOrWhiteSpace(contentType))
|
||||
contentType = DetermineContentType(content);
|
||||
|
||||
var contentWriter = context.GetServices<IHttpContentFactory>().FirstOrDefault(x => x.SupportsContentType(contentType)) ?? new TextContentFactory();
|
||||
var httpContent = contentWriter.CreateHttpContent(content, contentType);
|
||||
var factories = context.GetServices<IHttpContentFactory>();
|
||||
var factory = factories.FirstOrDefault(httpContentFactory => httpContentFactory.SupportedContentTypes.Any(c => c == contentType)) ?? new TextContentFactory();
|
||||
var httpContent = factory.CreateHttpContent(content, contentType);
|
||||
|
||||
// Set content type.
|
||||
response.ContentType = httpContent.Headers.ContentType?.ToString() ?? contentType;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
using System.Reflection;
|
||||
using Elsa.Http.ContentWriters;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
|
||||
namespace Elsa.Http.ActivityOptionProviders;
|
||||
|
||||
/// <summary>
|
||||
/// Provides options for the <see cref="SendHttpRequest"/> activity's <see cref="SendHttpRequest.ContentType"/> property.
|
||||
/// </summary>
|
||||
public class HttpContentTypeOptionsProvider : IActivityPropertyOptionsProvider
|
||||
{
|
||||
private readonly IEnumerable<IHttpContentFactory> _httpContentFactories;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="HttpContentTypeOptionsProvider"/> class.
|
||||
/// </summary>
|
||||
public HttpContentTypeOptionsProvider(IEnumerable<IHttpContentFactory> httpContentFactories)
|
||||
{
|
||||
_httpContentFactories = httpContentFactories;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask<IDictionary<string, object>> GetOptionsAsync(PropertyInfo property, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var contentTypes = _httpContentFactories.SelectMany(x => x.SupportedContentTypes).Distinct().OrderBy(x => x).ToArray();
|
||||
|
||||
var options = new Dictionary<string, object>
|
||||
{
|
||||
["items"] = new[] { "" }.Concat(contentTypes)
|
||||
};
|
||||
|
||||
return new(options);
|
||||
}
|
||||
}
|
||||
23
src/modules/Elsa.Http/ContentWriters/BinaryContentFactory.cs
Normal file
23
src/modules/Elsa.Http/ContentWriters/BinaryContentFactory.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
using System.Net.Mime;
|
||||
|
||||
namespace Elsa.Http.ContentWriters;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="HttpContent"/> object for application/octet-stream.
|
||||
/// </summary>
|
||||
public class BinaryContentFactory : IHttpContentFactory
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> SupportedContentTypes => new[] { MediaTypeNames.Application.Octet };
|
||||
|
||||
/// <inheritdoc />
|
||||
public HttpContent CreateHttpContent(object content, string contentType)
|
||||
{
|
||||
return content switch
|
||||
{
|
||||
byte[] bytes => new ByteArrayContent(bytes),
|
||||
Stream stream => new StreamContent(stream),
|
||||
_ => throw new NotSupportedException($"Content of type {content.GetType()} is not supported.")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -8,10 +8,8 @@ namespace Elsa.Http.ContentWriters;
|
|||
/// </summary>
|
||||
public class FormUrlEncodedHttpContentFactory : IHttpContentFactory
|
||||
{
|
||||
private readonly List<string> _supportedContentTypes = new() { "application/x-www-form-urlencoded" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SupportsContentType(string contentType) => _supportedContentTypes.Contains(contentType);
|
||||
public IEnumerable<string> SupportedContentTypes => new[] { "application/x-www-form-urlencoded" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public HttpContent CreateHttpContent(object content, string? contentType = null) => new FormUrlEncodedContent(GetContentAsDictionary(content));
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public interface IHttpContentFactory
|
|||
/// <summary>
|
||||
/// Returns a value indicating whether this factory supports the specified content type.
|
||||
/// </summary>
|
||||
bool SupportsContentType(string contentType);
|
||||
IEnumerable<string> SupportedContentTypes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a concrete <see cref="HttpContent"/> derivative based on the specified content type.
|
||||
|
|
|
|||
|
|
@ -10,10 +10,8 @@ namespace Elsa.Http.ContentWriters;
|
|||
/// </summary>
|
||||
public class JsonContentFactory : IHttpContentFactory
|
||||
{
|
||||
private readonly List<string> _supportedContentTypes = new() { MediaTypeNames.Application.Json, "text/json" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SupportsContentType(string contentType) => _supportedContentTypes.Contains(contentType);
|
||||
public IEnumerable<string> SupportedContentTypes => new[] { MediaTypeNames.Application.Json, "text/json" };
|
||||
|
||||
/// <inheritdoc />
|
||||
public HttpContent CreateHttpContent(object content, string contentType)
|
||||
|
|
|
|||
|
|
@ -8,16 +8,14 @@ namespace Elsa.Http.ContentWriters;
|
|||
/// </summary>
|
||||
public class TextContentFactory : IHttpContentFactory
|
||||
{
|
||||
private readonly List<string> _supportedContentTypes = new()
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> SupportedContentTypes => new[]
|
||||
{
|
||||
MediaTypeNames.Text.Plain,
|
||||
MediaTypeNames.Text.RichText,
|
||||
MediaTypeNames.Text.Html,
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SupportsContentType(string contentType) => _supportedContentTypes.Contains(contentType);
|
||||
|
||||
/// <inheritdoc />
|
||||
public HttpContent CreateHttpContent(object content, string contentType)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,14 +5,17 @@ using System.Xml.Serialization;
|
|||
namespace Elsa.Http.ContentWriters;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="HttpContent"/> object for application/json.
|
||||
/// Creates a <see cref="HttpContent"/> object for XML types.
|
||||
/// </summary>
|
||||
public class XmlContentFactory : IHttpContentFactory
|
||||
{
|
||||
private readonly List<string> _supportedContentTypes = new() { MediaTypeNames.Application.Xml, MediaTypeNames.Text.Xml };
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool SupportsContentType(string contentType) => _supportedContentTypes.Contains(contentType);
|
||||
public IEnumerable<string> SupportedContentTypes => new[]
|
||||
{
|
||||
MediaTypeNames.Application.Xml,
|
||||
MediaTypeNames.Text.Xml,
|
||||
MediaTypeNames.Application.Soap,
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public HttpContent CreateHttpContent(object content, string contentType)
|
||||
|
|
@ -20,7 +23,7 @@ public class XmlContentFactory : IHttpContentFactory
|
|||
var text = content as string ?? Serialize(content);
|
||||
return new StringContent(text, Encoding.UTF8, contentType);
|
||||
}
|
||||
|
||||
|
||||
private string Serialize(object value)
|
||||
{
|
||||
using var writer = new StringWriter();
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Elsa.Extensions;
|
|||
using Elsa.Features.Abstractions;
|
||||
using Elsa.Features.Attributes;
|
||||
using Elsa.Features.Services;
|
||||
using Elsa.Http.ActivityOptionProviders;
|
||||
using Elsa.Http.ContentWriters;
|
||||
using Elsa.Http.Contracts;
|
||||
using Elsa.Http.DownloadableContentHandlers;
|
||||
|
|
@ -14,7 +15,6 @@ using Elsa.Http.Models;
|
|||
using Elsa.Http.Options;
|
||||
using Elsa.Http.Parsers;
|
||||
using Elsa.Http.PortResolvers;
|
||||
using Elsa.Http.Providers;
|
||||
using Elsa.Http.Selectors;
|
||||
using Elsa.Http.Services;
|
||||
using Elsa.JavaScript.Features;
|
||||
|
|
@ -173,7 +173,7 @@ public class HttpFeature : FeatureBase
|
|||
.AddSingleton<IHttpContentFactory, FormUrlEncodedHttpContentFactory>()
|
||||
|
||||
// Activity property options providers.
|
||||
.AddSingleton<IActivityPropertyOptionsProvider, WriteHttpResponseContentTypeOptionsProvider>()
|
||||
.AddSingleton<IActivityPropertyOptionsProvider, HttpContentTypeOptionsProvider>()
|
||||
|
||||
// Port resolvers.
|
||||
.AddSingleton<IActivityPortResolver, SendHttpRequestActivityPortResolver>()
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
using System.Reflection;
|
||||
using Elsa.Http.Options;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.Http.Providers;
|
||||
|
||||
internal class WriteHttpResponseContentTypeOptionsProvider : IActivityPropertyOptionsProvider
|
||||
{
|
||||
private readonly HttpActivityOptions _options;
|
||||
|
||||
public WriteHttpResponseContentTypeOptionsProvider(IOptions<HttpActivityOptions> options)
|
||||
{
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
public ValueTask<IDictionary<string, object>> GetOptionsAsync(PropertyInfo property, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = new Dictionary<string, object>
|
||||
{
|
||||
["items"] = new[] { "" }.Concat(_options.AvailableContentTypes)
|
||||
};
|
||||
|
||||
return new(options);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue