Replace precompiled queries with extensions, process warnings and fix test

This commit is contained in:
Sipke Schoorstra 2020-11-03 10:50:32 +01:00
parent 13b770e362
commit 7f44bfe4c1
30 changed files with 127 additions and 273 deletions

View file

@ -46,7 +46,7 @@ namespace Elsa.Activities.Http
/// The URL to invoke.
/// </summary>
[ActivityProperty(Hint = "The URL to send the HTTP request to.")]
public PathString Url { get; set; }
public PathString? Url { get; set; }
/// <summary>
/// The HTTP method to use.
@ -56,7 +56,7 @@ namespace Elsa.Activities.Http
Hint = "The HTTP method to use when making the request."
)]
[SelectOptions("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD")]
public string Method { get; set; }
public string? Method { get; set; }
/// <summary>
/// The body to send along with the request.
@ -73,10 +73,10 @@ namespace Elsa.Activities.Http
Hint = "The content type to send with the request (if applicable)."
)]
[SelectOptions("text/plain", "text/html", "application/json", "application/xml")]
public string ContentType { get; set; }
public string? ContentType { get; set; }
[ActivityProperty(Hint = "The Authorization header value to send.")]
public string Authorization { get; set; }
public string? Authorization { get; set; }
/// <summary>
/// The headers to send along with the request.
@ -141,7 +141,8 @@ namespace Elsa.Activities.Http
private HttpRequestMessage CreateRequest()
{
var methodSupportsBody = GetMethodSupportsBody(Method);
var method = Method ?? HttpMethods.Get;
var methodSupportsBody = GetMethodSupportsBody(method);
var url = Url;
var request = new HttpRequestMessage(new HttpMethod(Method), url);
var authorizationHeaderValue = Authorization;

View file

@ -1,10 +0,0 @@
// ReSharper disable once CheckNamespace
namespace Elsa.Activities.Http
{
public static class SendHttpRequestBuilderExtensions
{
}
}

View file

@ -9,14 +9,13 @@ namespace Elsa.Activities.Http
{
public static class WriteHttpResponseBuilderExtensions
{
public static IActivityBuilder WriteHttpResponse(this IBuilder builder,
Action<ISetupActivity<WriteHttpResponse>> setup) => builder.Then(setup);
public static IActivityBuilder WriteHttpResponse(this IBuilder builder, Action<ISetupActivity<WriteHttpResponse>> setup) => builder.Then(setup);
public static IActivityBuilder WriteHttpResponse(
this IBuilder builder,
Func<ActivityExecutionContext, HttpStatusCode> statusCode,
Func<ActivityExecutionContext, ValueTask<string>> content,
Func<ActivityExecutionContext, string> contentType) =>
Func<ActivityExecutionContext, ValueTask<string?>> content,
Func<ActivityExecutionContext, string?> contentType) =>
builder.WriteHttpResponse(
setup => setup
.Set(x => x.StatusCode, statusCode)
@ -26,8 +25,8 @@ namespace Elsa.Activities.Http
public static IActivityBuilder WriteHttpResponse(
this IBuilder builder,
Func<ActivityExecutionContext, HttpStatusCode> statusCode,
Func<ActivityExecutionContext, string> content,
Func<ActivityExecutionContext, string> contentType) =>
Func<ActivityExecutionContext, string?> content,
Func<ActivityExecutionContext, string?> contentType) =>
builder.WriteHttpResponse(
setup => setup
.Set(x => x.StatusCode, statusCode)
@ -37,8 +36,8 @@ namespace Elsa.Activities.Http
public static IActivityBuilder WriteHttpResponse(
this IBuilder builder,
Func<HttpStatusCode> statusCode,
Func<string> content,
Func<string> contentType) =>
Func<string?> content,
Func<string?> contentType) =>
builder.WriteHttpResponse(
setup => setup
.Set(x => x.StatusCode, statusCode)
@ -48,8 +47,8 @@ namespace Elsa.Activities.Http
public static IActivityBuilder WriteHttpResponse(
this IBuilder builder,
HttpStatusCode statusCode,
string content,
string contentType) =>
string? content,
string? contentType) =>
builder.WriteHttpResponse(
setup => setup
.Set(x => x.StatusCode, statusCode)

View file

@ -9,7 +9,7 @@ namespace Elsa.Activities.Http.Extensions
{
public static class HttpRequestExtensions
{
public static async Task<byte[]> ReadContentAsBytesAsync(
public static async Task<byte[]?> ReadContentAsBytesAsync(
this HttpRequest request,
CancellationToken cancellationToken = default)
{
@ -25,12 +25,12 @@ namespace Elsa.Activities.Http.Extensions
return content;
}
public static async Task<string> ReadContentAsStringAsync(
public static async Task<string?> ReadContentAsStringAsync(
this HttpRequest request,
CancellationToken cancellationToken = default)
{
var bytes = await request.ReadContentAsBytesAsync(cancellationToken);
return Encoding.UTF8.GetString(bytes);
return bytes != null ? Encoding.UTF8.GetString(bytes) : default;
}
public static Uri ToAbsoluteUrl(this HttpRequest request, string relativePath)

View file

@ -5,11 +5,11 @@ namespace Elsa.Activities.Http.Models
{
public class HttpRequestModel
{
public Uri Path { get; set; }
public string Method { get; set; }
public IDictionary<string, StringValuesModel> QueryString { get; set; }
public IDictionary<string, StringValuesModel> Headers { get; set; }
public object Body { get; set; }
public T GetBody<T>() => (T)Body;
public Uri Path { get; set; } = default!;
public string Method { get; set; } = default!;
public IDictionary<string, StringValuesModel> QueryString { get; set; } = default!;
public IDictionary<string, StringValuesModel> Headers { get; set; } = default!;
public object? Body { get; set; }
public T GetBody<T>() => (T)Body!;
}
}

View file

@ -7,6 +7,6 @@ namespace Elsa.Activities.Http.Models
{
public HttpStatusCode StatusCode { get; set; }
public Dictionary<string, string[]> Headers { get; set; } = new Dictionary<string, string[]>();
public object Content { get; set; }
public object? Content { get; set; }
}
}

View file

@ -12,7 +12,7 @@ namespace Elsa.Activities.Http.Models
WorkflowInstanceId = workflowInstanceId;
}
public string Name { get; set; }
public string WorkflowInstanceId { get; set; }
public string Name { get; set; } = default!;
public string WorkflowInstanceId { get; set; } = default!;
}
}

View file

@ -4,8 +4,8 @@ namespace Elsa.Activities.Http.Models
{
public class StringValuesModel
{
public string Value { get; set; }
public string[] Values { get; set; }
public string? Value { get; set; }
public string[]? Values { get; set; }
public StringValuesModel()
{
@ -17,20 +17,17 @@ namespace Elsa.Activities.Http.Models
Values = value.Count != 1 ? value.ToArray() : default;
}
public override string ToString()
public override string? ToString()
{
if (Values == null)
return Value;
switch (Values.Length)
return Values.Length switch
{
case 0:
return null;
case 1:
return Values[0];
default:
return string.Join(",", Values);
}
0 => default,
1 => Values[0],
_ => string.Join(",", Values)
};
}
}
}

View file

@ -4,6 +4,6 @@ namespace Elsa.Activities.Http.Options
{
public class HttpActivityOptions
{
public Uri BaseUrl { get; set; }
public Uri BaseUrl { get; set; } = default!;
}
}

View file

@ -12,6 +12,6 @@ namespace Elsa.Activities.Http.Parsers
public int Priority => -1;
public string?[] SupportedContentTypes => new[] { "", default };
public async Task<object> ParseAsync(HttpRequest request, Type? targetType = default, CancellationToken cancellationToken = default) => await request.ReadContentAsStringAsync(cancellationToken);
public async Task<object?> ParseAsync(HttpRequest request, Type? targetType = default, CancellationToken cancellationToken = default) => await request.ReadContentAsStringAsync(cancellationToken);
}
}

View file

@ -9,9 +9,7 @@ namespace Elsa.Activities.Http.Parsers
public class DefaultHttpResponseBodyParser : IHttpResponseBodyParser
{
public int Priority => -1;
public IEnumerable<string> SupportedContentTypes => new[] { "", default };
public async Task<object> ParseAsync(HttpResponseMessage response, CancellationToken cancellationToken)
=> await response.Content.ReadAsStringAsync();
public IEnumerable<string?> SupportedContentTypes => new[] { "", default };
public async Task<object> ParseAsync(HttpResponseMessage response, CancellationToken cancellationToken) => await response.Content.ReadAsStringAsync();
}
}

View file

@ -21,9 +21,13 @@ namespace Elsa.Activities.Http.Parsers
public int Priority => 0;
public string?[] SupportedContentTypes => new[] { "application/json", "text/json" };
public async Task<object> ParseAsync(HttpRequest request, Type? targetType = default, CancellationToken cancellationToken = default)
public async Task<object?> ParseAsync(HttpRequest request, Type? targetType = default, CancellationToken cancellationToken = default)
{
var json = await request.ReadContentAsStringAsync(cancellationToken);
if (json == null)
return default;
targetType ??= typeof(ExpandoObject);
return _serializer.Deserialize(json, targetType)!;
}

View file

@ -11,7 +11,7 @@ namespace Elsa.Activities.Http.Parsers
public class JsonHttpResponseBodyParser : IHttpResponseBodyParser
{
public int Priority => 0;
public IEnumerable<string> SupportedContentTypes => new[] { "application/json", "text/json" };
public IEnumerable<string?> SupportedContentTypes => new[] { "application/json", "text/json" };
public async Task<object> ParseAsync(HttpResponseMessage response, CancellationToken cancellationToken)
{

View file

@ -16,7 +16,7 @@ namespace Elsa.Activities.Http.RequestHandlers.Results
Message = message;
}
public string Message { get; }
public string? Message { get; }
public async Task ExecuteResultAsync(HttpContext httpContext, RequestDelegate next)

View file

@ -9,6 +9,6 @@ namespace Elsa.Activities.Http.Services
{
int Priority { get; }
string?[] SupportedContentTypes { get; }
Task<object> ParseAsync(HttpRequest request, Type? targetType = default, CancellationToken cancellationToken = default);
Task<object?> ParseAsync(HttpRequest request, Type? targetType = default, CancellationToken cancellationToken = default);
}
}

View file

@ -8,7 +8,7 @@ namespace Elsa.Activities.Http.Services
public interface IHttpResponseBodyParser
{
int Priority { get; }
IEnumerable<string> SupportedContentTypes { get; }
IEnumerable<string?> SupportedContentTypes { get; }
Task<object> ParseAsync(HttpResponseMessage response, CancellationToken cancellationToken);
}
}

View file

@ -21,7 +21,7 @@ namespace Elsa.Activities.Http.Services
public bool TryDecryptToken<T>(string token, out T payload)
{
payload = default;
payload = default!;
try
{

View file

@ -0,0 +1,69 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Indexes;
using Elsa.Models;
using Elsa.Services;
using YesSql;
namespace Elsa.Extensions
{
public static class WorkflowDefinitionManagerExtensions
{
public static IQuery<WorkflowDefinition> QueryByIdAndVersion(this IWorkflowDefinitionManager manager, string workflowDefinitionId, VersionOptions versionOptions) =>
manager.Query<WorkflowDefinitionIndex>(x => x.WorkflowDefinitionId == workflowDefinitionId).WithVersion(versionOptions);
public static IQuery<WorkflowDefinition> QueryByVersionId(
this IWorkflowDefinitionManager manager,
string workflowDefinitionVersionId) =>
manager.Query<WorkflowDefinitionIndex>(x => x.WorkflowDefinitionVersionId == workflowDefinitionVersionId);
public static IQuery<WorkflowDefinition> QueryByVersion(
this IWorkflowDefinitionManager manager,
VersionOptions versionOptions) =>
manager.Query<WorkflowDefinitionIndex>().WithVersion(versionOptions);
public static IQuery<WorkflowInstance> QueryByBlockingActivity(
this IWorkflowInstanceManager manager,
string activityType) =>
manager.Query<WorkflowInstanceBlockingActivitiesIndex>(x => x.ActivityType == activityType);
public static async Task<WorkflowDefinition?> GetAsync(
this IWorkflowDefinitionManager manager,
string workflowDefinitionId,
VersionOptions versionOptions,
CancellationToken cancellationToken = default) =>
await manager.QueryByIdAndVersion(workflowDefinitionId, versionOptions).FirstOrDefaultAsync();
public static async Task<WorkflowDefinition?> GetByVersionIdAsync(
this IWorkflowDefinitionManager manager,
string workflowDefinitionVersionId,
CancellationToken cancellationToken = default) =>
await manager.QueryByVersionId(workflowDefinitionVersionId).FirstOrDefaultAsync();
public static async Task<IEnumerable<WorkflowDefinition>> ListAsync(
this IWorkflowDefinitionManager manager,
VersionOptions versionOptions,
CancellationToken cancellationToken = default) =>
await manager.QueryByVersion(versionOptions).ListAsync();
public static Task<IEnumerable<WorkflowInstance>> ListByStatusAsync(
this IWorkflowInstanceManager manager,
WorkflowStatus workflowStatus,
CancellationToken cancellationToken = default) =>
manager
.Query<WorkflowInstanceIndex>(x => x.WorkflowStatus == workflowStatus)
.ListAsync();
public static async Task<IEnumerable<WorkflowInstance>> ListByBlockingActivityAsync(
this IWorkflowInstanceManager manager,
string activityType,
CancellationToken cancellationToken = default) =>
await manager.QueryByBlockingActivity(activityType).ListAsync();
public static async Task<IEnumerable<WorkflowInstance>> ListByBlockingActivityAsync<TActivity>(
this IWorkflowInstanceManager manager,
CancellationToken cancellationToken = default) =>
await manager.ListByBlockingActivityAsync(typeof(TActivity).Name, cancellationToken);
}
}

View file

@ -1,46 +0,0 @@
using System;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Extensions;
using Elsa.Indexes;
using Elsa.Models;
using Elsa.Services;
using YesSql;
namespace Elsa.Queries
{
public class WorkflowDefinitionByIdAndVersionQuery : ICompiledQuery<WorkflowDefinition>
{
public string WorkflowDefinitionId { get; }
public VersionOptions VersionOptions { get; }
public WorkflowDefinitionByIdAndVersionQuery(string workflowDefinitionId, VersionOptions versionOptions)
{
WorkflowDefinitionId = workflowDefinitionId;
VersionOptions = versionOptions;
}
public Expression<Func<IQuery<WorkflowDefinition>, IQuery<WorkflowDefinition>>> Query() =>
query => query
.With<WorkflowDefinitionIndex>(x => x.WorkflowDefinitionId == WorkflowDefinitionId)
.WithVersion(VersionOptions);
}
public static class WorkflowDefinitionByIdAndVersionQueryWorkflowDefinitionManagerExtensions
{
public static IQuery<WorkflowDefinition> QueryByIdAndVersion(
this IWorkflowDefinitionManager manager,
string workflowDefinitionId,
VersionOptions versionOptions) =>
manager.Query<WorkflowDefinitionIndex>(x => x.WorkflowDefinitionId == workflowDefinitionId).WithVersion(versionOptions);
//manager.ExecuteQuery(new WorkflowDefinitionByIdAndVersionQuery(workflowDefinitionId, versionOptions));
public static async Task<WorkflowDefinition?> GetAsync(
this IWorkflowDefinitionManager manager,
string workflowDefinitionId,
VersionOptions versionOptions,
CancellationToken cancellationToken = default) =>
await manager.QueryByIdAndVersion(workflowDefinitionId, versionOptions).FirstOrDefaultAsync();
}
}

View file

@ -1,38 +0,0 @@
using System;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Indexes;
using Elsa.Models;
using Elsa.Services;
using YesSql;
namespace Elsa.Queries
{
public class WorkflowDefinitionByVersionIdQuery : ICompiledQuery<WorkflowDefinition>
{
public string WorkflowDefinitionVersionId { get; }
public WorkflowDefinitionByVersionIdQuery(string workflowDefinitionVersionId) =>
WorkflowDefinitionVersionId = workflowDefinitionVersionId;
public Expression<Func<IQuery<WorkflowDefinition>, IQuery<WorkflowDefinition>>> Query()
{
return query => query
.With<WorkflowDefinitionIndex>(x => x.WorkflowDefinitionVersionId == WorkflowDefinitionVersionId);
}
}
public static class WorkflowDefinitionByVersionIdQueryWorkflowDefinitionManagerExtensions
{
public static IQuery<WorkflowDefinition> QueryByVersionId(this IWorkflowDefinitionManager manager,
string workflowDefinitionVersionId) =>
manager.ExecuteQuery(new WorkflowDefinitionByVersionIdQuery(workflowDefinitionVersionId));
public static async Task<WorkflowDefinition?> GetByVersionIdAsync(
this IWorkflowDefinitionManager manager,
string workflowDefinitionVersionId,
CancellationToken cancellationToken = default) =>
await manager.QueryByVersionId(workflowDefinitionVersionId).FirstOrDefaultAsync();
}
}

View file

@ -1,35 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Extensions;
using Elsa.Models;
using Elsa.Services;
using YesSql;
namespace Elsa.Queries
{
public class WorkflowDefinitionByVersionQuery : ICompiledQuery<WorkflowDefinition>
{
public VersionOptions VersionOptions { get; }
public WorkflowDefinitionByVersionQuery(VersionOptions versionOptions) => VersionOptions = versionOptions;
public Expression<Func<IQuery<WorkflowDefinition>, IQuery<WorkflowDefinition>>> Query() =>
query => query.WithVersion(VersionOptions);
}
public static class WorkflowDefinitionByVersionQueryWorkflowDefinitionManagerExtensions
{
public static IQuery<WorkflowDefinition> QueryByVersion(this IWorkflowDefinitionManager manager,
VersionOptions versionOptions) =>
manager.ExecuteQuery(
new WorkflowDefinitionByVersionQuery(versionOptions));
public static async Task<IEnumerable<WorkflowDefinition>> ListAsync(
this IWorkflowDefinitionManager manager,
VersionOptions versionOptions,
CancellationToken cancellationToken = default) =>
await manager.QueryByVersion(versionOptions).ListAsync();
}
}

View file

@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Indexes;
using Elsa.Models;
using Elsa.Services;
using YesSql;
namespace Elsa.Queries
{
public class WorkflowInstanceByBlockingActivityQuery : ICompiledQuery<WorkflowInstance>
{
public string ActivityType { get; }
public WorkflowInstanceByBlockingActivityQuery(string activityType)
{
ActivityType = activityType;
}
public Expression<Func<IQuery<WorkflowInstance>, IQuery<WorkflowInstance>>> Query() => query =>
query.With<WorkflowInstanceBlockingActivitiesIndex>().Where(
x => x.ActivityType == ActivityType);
}
public static class WorkflowInstanceByBlockingActivityQueryWorkflowInstanceManagerExtensions
{
public static IQuery<WorkflowInstance> QueryByBlockingActivity(
this IWorkflowInstanceManager manager,
string activityType) =>
manager
.ExecuteQuery(
new WorkflowInstanceByBlockingActivityQuery(activityType));
public static async Task<IEnumerable<WorkflowInstance>> ListByBlockingActivityAsync(
this IWorkflowInstanceManager manager,
string activityType,
CancellationToken cancellationToken = default) =>
await manager.QueryByBlockingActivity(activityType).ListAsync();
public static async Task<IEnumerable<WorkflowInstance>> ListByBlockingActivityAsync<TActivity>(
this IWorkflowInstanceManager manager,
CancellationToken cancellationToken = default) =>
await manager.ListByBlockingActivityAsync(typeof(TActivity).Name, cancellationToken);
}
}

View file

@ -1,38 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Indexes;
using Elsa.Models;
using Elsa.Services;
using YesSql;
namespace Elsa.Queries
{
public class WorkflowInstanceByStatusQuery : ICompiledQuery<WorkflowInstance>
{
public WorkflowStatus Status { get; }
public WorkflowInstanceByStatusQuery(WorkflowStatus status)
{
Status = status;
}
public Expression<Func<IQuery<WorkflowInstance>, IQuery<WorkflowInstance>>> Query() => query =>
query.With<WorkflowInstanceIndex>().Where(
x => x.WorkflowStatus == Status);
}
public static class WorkflowInstanceByStatusQueryWorkflowInstanceManagerExtensions
{
public static Task<IEnumerable<WorkflowInstance>> ListByStatusAsync(
this IWorkflowInstanceManager manager,
WorkflowStatus workflowStatus,
CancellationToken cancellationToken = default) =>
manager
.ExecuteQuery(
new WorkflowInstanceByStatusQuery(workflowStatus))
.ListAsync();
}
}

View file

@ -1,7 +1,7 @@
using System.Threading;
using System.Threading.Tasks;
using Elsa.Extensions;
using Elsa.Models;
using Elsa.Queries;
namespace Elsa.Services
{

View file

@ -1,8 +1,8 @@
using System.Threading;
using System.Threading.Tasks;
using Elsa.DistributedLock;
using Elsa.Extensions;
using Elsa.Models;
using Elsa.Queries;
using Elsa.Services;
namespace Elsa.StartupTasks

View file

@ -4,8 +4,8 @@ namespace Elsa.Samples.ContextualWorkflowHttp.Models
{
public class Comment
{
public string Author { get; set; }
public string Author { get; set; } = default!;
public Instant Timestamp { get; set; }
public string Text { get; set; }
public string Text { get; set; } = default!;
}
}

View file

@ -28,7 +28,7 @@ namespace Elsa.Samples.ContextualWorkflowHttp.Workflows
.ReceiveHttpPostRequest<Document>("/documents")
// Store the document as the workflow context. It will be saved automatically when the workflow gets suspended.
.Then(context => context.WorkflowExecutionContext.WorkflowContext = (Document)((HttpRequestModel)context.Input!).Body)
.Then(context => context.WorkflowExecutionContext.WorkflowContext = (Document)((HttpRequestModel)context.Input!).Body!)
// Write an HTTP response.
.WriteHttpResponse(
@ -63,7 +63,7 @@ namespace Elsa.Samples.ContextualWorkflowHttp.Workflows
private static void StoreComment(ActivityExecutionContext context)
{
var document = (Document)context.WorkflowExecutionContext.WorkflowContext!;
var comment = (Comment)((HttpRequestModel)context.Input)!.Body;
var comment = (Comment)((HttpRequestModel)context.Input)!.Body!;
document.Comments.Add(comment);
}

View file

@ -1,7 +1,7 @@
using System.Threading;
using System.Threading.Tasks;
using Elsa.Extensions;
using Elsa.Models;
using Elsa.Queries;
using Elsa.Serialization;
using Elsa.Services;
using Microsoft.AspNetCore.Mvc;

View file

@ -7,7 +7,7 @@ namespace Elsa.ComponentTests.Helpers
{
public class ElsaHostApplicationFactory : WebApplicationFactory<Startup>
{
private string _dbConnectionString;
private string _dbConnectionString = default!;
public void SetDbConnectionString(string connectionString)
{

View file

@ -15,7 +15,7 @@
"$values": [
{
"$id": "4",
"id": "activity-1",
"activityId": "activity-1",
"type": "WriteLine",
"properties": {
"$id": "5",