< Summary

Information
Class: Elsa.Http.HttpEndpoint
Assembly: Elsa.Http
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Http/Activities/HttpEndpoint.cs
Line coverage
40%
Covered lines: 88
Uncovered lines: 130
Coverable lines: 218
Total lines: 520
Line coverage: 40.3%
Branch coverage
19%
Covered branches: 12
Total branches: 62
Branch coverage: 19.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Http/Activities/HttpEndpoint.cs

#LineLine coverage
 1using System.Runtime.CompilerServices;
 2using System.Text.Json;
 3using Elsa.Expressions.Models;
 4using Elsa.Extensions;
 5using Elsa.Http.Bookmarks;
 6using Elsa.Http.Extensions;
 7using Elsa.Http.UIHints;
 8using Elsa.Workflows;
 9using Elsa.Workflows.Attributes;
 10using Elsa.Workflows.UIHints;
 11using Elsa.Workflows.Models;
 12using Microsoft.AspNetCore.Http;
 13using Microsoft.AspNetCore.Routing;
 14using Microsoft.Extensions.DependencyInjection;
 15
 16namespace Elsa.Http;
 17
 18/// <summary>
 19/// Wait for an inbound HTTP request that matches the specified path and methods.
 20/// </summary>
 21[Activity("Elsa", "HTTP", "Wait for an inbound HTTP request that matches the specified path and methods.", DisplayName =
 22[Output(IsSerializable = false)]
 23public class HttpEndpoint : Trigger<HttpRequest>
 24{
 25    internal const string HttpContextInputKey = "HttpContext";
 26    internal const string PathInputKey = "Path";
 27
 28    /// <inheritdoc />
 34629    public HttpEndpoint([CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : base(source, line
 30    {
 34631    }
 32
 33    /// <inheritdoc />
 034    public HttpEndpoint(Input<string> path, Input<string> method, [CallerFilePath] string? source = null, [CallerLineNum
 35    {
 036        Path = path;
 037        SupportedMethods = new(ObjectLiteral.From(new[] { method }));
 038    }
 39
 40    /// <inheritdoc />
 041    public HttpEndpoint(Input<string> path, [CallerFilePath] string? source = null, [CallerLineNumber] int? line = null)
 42    {
 043        Path = path;
 044    }
 45
 46    /// <summary>
 47    /// The path to associate with the workflow.
 48    /// </summary>
 49    [Input(
 50        Description = "The path to associate with the workflow.",
 51        UIHint = InputUIHints.SingleLine,
 52        UIHandler = typeof(HttpEndpointPathUIHandler)
 53    )]
 136454    public Input<string> Path { get; set; } = null!;
 55
 56    /// <summary>
 57    /// The HTTP methods to accept.
 58    /// </summary>
 59    [Input(
 60        Description = "The HTTP methods to accept.",
 61        Options = new[] { "GET", "POST", "PUT", "HEAD", "DELETE" },
 62        UIHint = InputUIHints.CheckList)]
 171063    public Input<ICollection<string>> SupportedMethods { get; set; } = new(ObjectLiteral.From(new[] { HttpMethods.Get })
 64
 65    /// <summary>
 66    /// Allow authenticated requests only.
 67    /// </summary>
 68    [Input(Description = "Allow authenticated requests only.", Category = "Security")]
 144169    public Input<bool> Authorize { get; set; } = new(false);
 70
 71    /// <summary>
 72    /// Provide a policy to evaluate. If the policy fails, the request is forbidden.
 73    /// </summary>
 74    [Input(Description = "Provide a policy to evaluate. If the policy fails, the request is forbidden.", Category = "Sec
 144175    public Input<string?> Policy { get; set; } = new(default(string?));
 76
 77    /// <summary>
 78    /// The maximum time allowed to process the request.
 79    /// </summary>
 80    [Input(Description = "The maximum time allowed to process the request.", Category = "Upload")]
 109581    public Input<TimeSpan?> RequestTimeout { get; set; } = null!;
 82
 83    /// <summary>
 84    /// The maximum request size allowed in bytes.
 85    /// </summary>
 86    [Input(Description = "The maximum request size allowed in bytes.", Category = "Upload")]
 130987    public Input<long?> RequestSizeLimit { get; set; } = null!;
 88
 89    /// <summary>
 90    /// The maximum request size allowed in bytes.
 91    /// </summary>
 92    [Input(Description = "The maximum file size allowed in bytes for an individual file.", Category = "Upload")]
 103893    public Input<long?> FileSizeLimit { get; set; } = null!;
 94
 95    /// <summary>
 96    /// The allowed file extensions,
 97    /// </summary>
 98    [Input(Description = "Only file extensions in this list are allowed. Leave empty to allow all extensions", Category 
 103899    public Input<ICollection<string>> AllowedFileExtensions { get; set; } = null!;
 100
 101    /// <summary>
 102    /// The allowed file extensions,
 103    /// </summary>
 104    [Input(Description = "File extensions in this list are forbidden. Leave empty to not block any extension.", Category
 1038105    public Input<ICollection<string>> BlockedFileExtensions { get; set; } = null!;
 106
 107    /// <summary>
 108    /// The allowed file extensions,
 109    /// </summary>
 110    [Input(Description = "Only MIME types in this list are allowed. Leave empty to allow all types", Category = "Upload"
 1038111    public Input<ICollection<string>> AllowedMimeTypes { get; set; } = null!;
 112
 113    /// <summary>
 114    /// A value indicating whether to expose the "Request too large" outcome.
 115    /// </summary>
 116    [Input(Description = "A value indicating whether to expose the \"Request too large\" outcome.", Category = "Outcomes
 583117    public bool ExposeRequestTooLargeOutcome { get; set; }
 118
 119    /// <summary>
 120    /// A value indicating whether to expose the "File too large" outcome.
 121    /// </summary>
 122    [Input(Description = "A value indicating whether to expose the \"File too large\" outcome.", Category = "Outcomes")]
 583123    public bool ExposeFileTooLargeOutcome { get; set; }
 124
 125    /// <summary>
 126    /// A value indicating whether to expose the "Invalid file extension" outcome.
 127    /// </summary>
 128    [Input(Description = "A value indicating whether to expose the \"Invalid file extension\" outcome.", Category = "Out
 583129    public bool ExposeInvalidFileExtensionOutcome { get; set; }
 130
 131    /// <summary>
 132    /// A value indicating whether to expose the "Invalid file MIME type" outcome.
 133    /// </summary>
 134    [Input(Description = "A value indicating whether to expose the \"Invalid file MIME type\" outcome.", Category = "Out
 583135    public bool ExposeInvalidFileMimeTypeOutcome { get; set; }
 136
 137    /// <summary>
 138    /// The parsed request content, if any.
 139    /// </summary>
 140    [Output(Description = "The parsed request content, if any.")]
 1197141    public Output<object?> ParsedContent { get; set; } = null!;
 142
 143    /// <summary>
 144    /// The uploaded files, if any.
 145    /// </summary>
 146    [Output(Description = "The uploaded files, if any.", IsSerializable = false)]
 761147    public Output<IFormFile[]> Files { get; set; } = null!;
 148
 149    /// <summary>
 150    /// The first uploaded file, if any.
 151    /// </summary>
 152    [Output(Description = "The first uploaded file, if any.", IsSerializable = false)]
 476153    public Output<IFormFile?> File { get; set; } = null!;
 154
 155    /// <summary>
 156    /// The parsed route data, if any.
 157    /// </summary>
 158    [Output(Description = "The parsed route data, if any.")]
 998159    public Output<IDictionary<string, object>> RouteData { get; set; } = null!;
 160
 161    /// <summary>
 162    /// The querystring data, if any.
 163    /// </summary>
 164    [Output(Description = "The querystring data, if any.")]
 981165    public Output<IDictionary<string, object>> QueryStringData { get; set; } = null!;
 166
 167    /// <summary>
 168    /// The headers, if any.
 169    /// </summary>
 170    [Output(Description = "The headers, if any.")]
 981171    public Output<IDictionary<string, object>> Headers { get; set; } = null!;
 172
 173    /// <inheritdoc />
 174    protected override IEnumerable<object> GetTriggerPayloads(TriggerIndexingContext context)
 175    {
 57176        context.TriggerName = HttpStimulusNames.HttpEndpoint;
 57177        return GetBookmarkPayloads(context.ExpressionExecutionContext);
 178    }
 179
 180    /// <inheritdoc />
 181    protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
 182    {
 218183        var path = Path.Get(context);
 218184        var methods = SupportedMethods.GetOrDefault(context) ?? new List<string> { HttpMethods.Get };
 218185        await context.WaitForHttpRequestAsync(path, methods, OnResumeAsync);
 218186    }
 187
 188    private async ValueTask OnResumeAsync(ActivityExecutionContext context)
 189    {
 214190        var httpContextAccessor = context.GetRequiredService<IHttpContextAccessor>();
 214191        var httpContext = httpContextAccessor.HttpContext;
 192
 214193        if (httpContext == null)
 194        {
 195            // We're executing in a non-HTTP context (e.g. in a virtual actor).
 196            // Create a bookmark to allow the invoker to export the state and resume execution from there.
 0197            context.CreateCrossBoundaryBookmark();
 0198            return;
 199        }
 200
 214201        await HandleRequestAsync(context);
 214202    }
 203
 204    private async Task HandleRequestAsync(ActivityExecutionContext context)
 205    {
 214206        var httpContextAccessor = context.GetRequiredService<IHttpContextAccessor>();
 214207        var httpContext = httpContextAccessor.HttpContext!;
 208
 209        // Provide the received HTTP request as output.
 214210        var request = httpContext.Request;
 214211        context.Set(Result, request);
 212
 213        // Read route data, if any.
 214214        var path = context.GetWorkflowInput<PathString>(PathInputKey);
 214215        var routeData = GetRouteData(httpContext, path);
 216216        var routeDictionary = routeData.Values.ToDictionary(route => route.Key, route => route.Value!);
 214217        var queryStringDictionary = httpContext.Request.Query.ToObjectDictionary();
 214218        var headersDictionary = httpContext.Request.Headers.ToObjectDictionary();
 219
 214220        context.Set(RouteData, routeDictionary);
 214221        context.Set(QueryStringData, queryStringDictionary);
 214222        context.Set(Headers, headersDictionary);
 223
 224        // Validate request size.
 214225        if (!ValidateRequestSize(context, httpContext))
 226        {
 0227            await HandleRequestTooLargeAsync(context, httpContext);
 0228            return;
 229        }
 230
 231        // Handle Form Fields
 214232        if (request.HasFormContentType)
 233        {
 0234            var formFields = request.Form.ToObjectDictionary();
 235
 0236            ParsedContent.Set(context, formFields);
 237
 238            // Read files, if any.
 0239            var files = ReadFilesAsync(context, request);
 240
 0241            if (files.Any())
 242            {
 0243                if (!ValidateFileSizes(context, httpContext, files))
 244                {
 0245                    await HandleFileSizeTooLargeAsync(context, httpContext);
 0246                    return;
 247                }
 248
 0249                if (!ValidateFileExtensionWhitelist(context, httpContext, files))
 250                {
 0251                    await HandleInvalidFileExtensionWhitelistAsync(context, httpContext);
 0252                    return;
 253                }
 254
 0255                if (!ValidateFileExtensionBlacklist(context, httpContext, files))
 256                {
 0257                    await HandleInvalidFileExtensionBlacklistAsync(context, httpContext);
 0258                    return;
 259                }
 260
 0261                if (!ValidateFileMimeTypes(context, httpContext, files))
 262                {
 0263                    await HandleInvalidFileMimeTypesAsync(context, httpContext);
 0264                    return;
 265                }
 266
 0267                Files.Set(context, files.ToArray());
 0268                File.Set(context, files.FirstOrDefault());
 269            }
 270        }
 271        else
 272        {
 273            // Parse Non-Form content.
 274            try
 275            {
 214276                var content = await ParseContentAsync(context, request);
 214277                ParsedContent.Set(context, content);
 214278            }
 0279            catch (JsonException e)
 280            {
 0281                await HandleInvalidJsonPayloadAsync(context, httpContext, e);
 0282                throw;
 283            }
 284
 285        }
 286
 287        // Complete.
 214288        await context.CompleteActivityAsync();
 214289    }
 290
 291    private IFormFileCollection ReadFilesAsync(ActivityExecutionContext context, HttpRequest request)
 292    {
 0293        return request.HasFormContentType ? request.Form.Files : new FormFileCollection();
 294    }
 295
 296    private bool ValidateRequestSize(ActivityExecutionContext context, HttpContext httpContext)
 297    {
 214298        var requestSizeLimit = RequestSizeLimit.GetOrDefault(context);
 299
 214300        if (!requestSizeLimit.HasValue)
 214301            return true;
 302
 0303        var requestSize = httpContext.Request.ContentLength ?? 0;
 0304        return requestSize <= requestSizeLimit;
 305    }
 306
 307    private async Task HandleRequestTooLargeAsync(ActivityExecutionContext context, HttpContext httpContext)
 308    {
 0309        var exposeRequestTooLargeOutcome = ExposeRequestTooLargeOutcome;
 310
 0311        if (exposeRequestTooLargeOutcome)
 312        {
 0313            await context.CompleteActivityWithOutcomesAsync("Request too large");
 314        }
 315        else
 316        {
 0317            var response = httpContext.Response;
 0318            response.StatusCode = StatusCodes.Status413PayloadTooLarge;
 0319            await response.WriteAsJsonAsync(new
 0320            {
 0321                Message = $"The maximum request size allowed is {RequestSizeLimit.Get(context)} bytes."
 0322            });
 0323            await response.Body.FlushAsync();
 0324        }
 0325    }
 326
 327    private bool ValidateFileSizes(ActivityExecutionContext context, HttpContext httpContext, IFormFileCollection files)
 328    {
 0329        var fileSizeLimit = FileSizeLimit.GetOrDefault(context);
 330
 0331        if (!fileSizeLimit.HasValue)
 0332            return true;
 333
 0334        if (!files.Any(file => file.Length > fileSizeLimit.Value))
 0335            return true;
 336
 0337        return false;
 338    }
 339
 340    private async Task HandleFileSizeTooLargeAsync(ActivityExecutionContext context, HttpContext httpContext)
 341    {
 0342        var exposeFileTooLargeOutcome = ExposeFileTooLargeOutcome;
 343
 0344        if (exposeFileTooLargeOutcome)
 345        {
 0346            await context.CompleteActivityWithOutcomesAsync("File too large");
 347        }
 348        else
 349        {
 0350            var response = httpContext.Response;
 0351            response.StatusCode = StatusCodes.Status413PayloadTooLarge;
 0352            await response.WriteAsJsonAsync(new
 0353            {
 0354                Message = $"The maximum file size allowed is {FileSizeLimit.Get(context)} bytes."
 0355            });
 0356            await response.Body.FlushAsync();
 0357        }
 0358    }
 359
 360    private bool ValidateFileExtensionWhitelist(ActivityExecutionContext context, HttpContext httpContext, IFormFileColl
 361    {
 0362        var allowedFileExtensions = AllowedFileExtensions.GetOrDefault(context);
 363
 0364        if (allowedFileExtensions == null || !allowedFileExtensions.Any())
 0365            return true;
 366
 0367        if (files.All(file => allowedFileExtensions.Contains(System.IO.Path.GetExtension(file.FileName), StringComparer.
 0368            return true;
 369
 0370        return false;
 371    }
 372
 373    private async Task HandleInvalidFileExtensionWhitelistAsync(ActivityExecutionContext context, HttpContext httpContex
 374    {
 0375        if (ExposeInvalidFileExtensionOutcome)
 376        {
 0377            await context.CompleteActivityWithOutcomesAsync("Invalid file extension");
 0378            return;
 379        }
 380
 0381        var response = httpContext.Response;
 0382        var allowedFileExtensions = AllowedFileExtensions.GetOrDefault(context)!;
 0383        response.StatusCode = StatusCodes.Status415UnsupportedMediaType;
 0384        await response.WriteAsJsonAsync(new
 0385        {
 0386            Message = $"Only the following file extensions are allowed: {string.Join(", ", allowedFileExtensions)}"
 0387        });
 0388        await response.Body.FlushAsync();
 0389    }
 390
 391    private bool ValidateFileExtensionBlacklist(ActivityExecutionContext context, HttpContext httpContext, IFormFileColl
 392    {
 0393        var blockedFileExtensions = BlockedFileExtensions.GetOrDefault(context);
 394
 0395        if (blockedFileExtensions == null || !blockedFileExtensions.Any())
 0396            return true;
 397
 0398        if (!files.Any(file => blockedFileExtensions.Contains(System.IO.Path.GetExtension(file.FileName), StringComparer
 0399            return true;
 400
 0401        return false;
 402    }
 403
 404    private async Task HandleInvalidFileExtensionBlacklistAsync(ActivityExecutionContext context, HttpContext httpContex
 405    {
 0406        if (ExposeInvalidFileExtensionOutcome)
 407        {
 0408            await context.CompleteActivityWithOutcomesAsync("Invalid file extension");
 0409            return;
 410        }
 411
 0412        var blockedFileExtensions = BlockedFileExtensions.GetOrDefault(context)!;
 0413        var response = httpContext.Response;
 0414        response.StatusCode = StatusCodes.Status415UnsupportedMediaType;
 0415        await response.WriteAsJsonAsync(new
 0416        {
 0417            Message = $"The following file extensions are not allowed: {string.Join(", ", blockedFileExtensions)}"
 0418        });
 0419        await response.Body.FlushAsync();
 0420    }
 421
 422    private bool ValidateFileMimeTypes(ActivityExecutionContext context, HttpContext httpContext, IFormFileCollection fi
 423    {
 0424        var allowedMimeTypes = AllowedMimeTypes.GetOrDefault(context);
 425
 0426        if (allowedMimeTypes == null || !allowedMimeTypes.Any())
 0427            return true;
 428
 0429        if (files.All(file => allowedMimeTypes.Contains(file.ContentType, StringComparer.OrdinalIgnoreCase)))
 0430            return true;
 431
 0432        return false;
 433    }
 434
 435    private async Task HandleInvalidFileMimeTypesAsync(ActivityExecutionContext context, HttpContext httpContext)
 436    {
 0437        if (ExposeInvalidFileMimeTypeOutcome)
 438        {
 0439            await context.CompleteActivityWithOutcomesAsync("Invalid file MIME type");
 0440            return;
 441        }
 442
 0443        var allowedMimeTypes = AllowedMimeTypes.GetOrDefault(context)!;
 0444        var response = httpContext.Response;
 0445        response.StatusCode = StatusCodes.Status415UnsupportedMediaType;
 0446        await response.WriteAsJsonAsync(new
 0447        {
 0448            Message = $"Only the following MIME types are allowed: {string.Join(", ", allowedMimeTypes)}"
 0449        });
 0450        await response.Body.FlushAsync();
 0451    }
 452
 453    private async Task HandleInvalidJsonPayloadAsync(ActivityExecutionContext context, HttpContext httpContext, JsonExce
 454    {
 0455        var response = httpContext.Response;
 0456        response.StatusCode = StatusCodes.Status400BadRequest;
 0457        await response.WriteAsJsonAsync(new
 0458        {
 0459            exception.Message,
 0460            exception.Path,
 0461            exception.LineNumber,
 0462        });
 0463        await response.Body.FlushAsync();
 0464    }
 465
 466    private async Task<object?> ParseContentAsync(ActivityExecutionContext context, HttpRequest httpRequest)
 467    {
 214468        if (!HasContent(httpRequest))
 14469            return null;
 470
 200471        var cancellationToken = context.CancellationToken;
 200472        var targetType = ParsedContent.GetTargetType(context);
 200473        var contentStream = httpRequest.Body;
 200474        var contentType = httpRequest.ContentType!;
 1800475        var headers = httpRequest.Headers.ToDictionary(x => x.Key, x => x.Value.ToArray());
 476
 200477        return await context.ParseContentAsync(contentStream, contentType, targetType, headers!, cancellationToken);
 214478    }
 479
 214480    private static bool HasContent(HttpRequest httpRequest) => httpRequest.Headers.ContentLength > 0;
 481
 482    private IEnumerable<object> GetBookmarkPayloads(ExpressionExecutionContext context)
 483    {
 484        // Generate bookmark data for path and selected methods.
 57485        var normalizedRoute = context.Get(Path)!.NormalizeRoute();
 57486        var methods = SupportedMethods.GetOrDefault(context) ?? new List<string> { HttpMethods.Get };
 57487        var authorize = Authorize.GetOrDefault(context);
 57488        var policy = Policy.GetOrDefault(context);
 57489        var requestTimeout = RequestTimeout.GetOrDefault(context);
 57490        var requestSizeLimit = RequestSizeLimit.GetOrDefault(context);
 491
 57492        return methods
 57493            .Select(x => new HttpEndpointBookmarkPayload(normalizedRoute, x.ToLowerInvariant(), authorize, policy, reque
 57494            .Cast<object>()
 57495            .ToArray();
 496    }
 497
 498    private static RouteData GetRouteData(HttpContext httpContext, string path)
 499    {
 214500        var routeData = httpContext.GetRouteData();
 214501        var routeTable = httpContext.RequestServices.GetRequiredService<IRouteTable>();
 214502        var routeMatcher = httpContext.RequestServices.GetRequiredService<IRouteMatcher>();
 503
 214504        var matchingRouteQuery =
 214505            from route in routeTable
 680506            let routeValues = routeMatcher.Match(route.Route, path)
 680507            where routeValues != null
 428508            select new { route, routeValues };
 509
 214510        var matchingRoute = matchingRouteQuery.FirstOrDefault();
 511
 214512        if (matchingRoute == null)
 0513            return routeData;
 514
 430515        foreach (var (key, value) in matchingRoute.routeValues!)
 1516            routeData.Values[key] = value;
 517
 214518        return routeData;
 519    }
 520}

Methods/Properties

.ctor(System.String,System.Nullable`1<System.Int32>)
.ctor(Elsa.Workflows.Models.Input`1<System.String>,Elsa.Workflows.Models.Input`1<System.String>,System.String,System.Nullable`1<System.Int32>)
.ctor(Elsa.Workflows.Models.Input`1<System.String>,System.String,System.Nullable`1<System.Int32>)
get_Path()
get_SupportedMethods()
get_Authorize()
get_Policy()
get_RequestTimeout()
get_RequestSizeLimit()
get_FileSizeLimit()
get_AllowedFileExtensions()
get_BlockedFileExtensions()
get_AllowedMimeTypes()
get_ExposeRequestTooLargeOutcome()
get_ExposeFileTooLargeOutcome()
get_ExposeInvalidFileExtensionOutcome()
get_ExposeInvalidFileMimeTypeOutcome()
get_ParsedContent()
get_Files()
get_File()
get_RouteData()
get_QueryStringData()
get_Headers()
GetTriggerPayloads(Elsa.Workflows.TriggerIndexingContext)
ExecuteAsync()
OnResumeAsync()
HandleRequestAsync()
ReadFilesAsync(Elsa.Workflows.ActivityExecutionContext,Microsoft.AspNetCore.Http.HttpRequest)
ValidateRequestSize(Elsa.Workflows.ActivityExecutionContext,Microsoft.AspNetCore.Http.HttpContext)
HandleRequestTooLargeAsync()
ValidateFileSizes(Elsa.Workflows.ActivityExecutionContext,Microsoft.AspNetCore.Http.HttpContext,Microsoft.AspNetCore.Http.IFormFileCollection)
HandleFileSizeTooLargeAsync()
ValidateFileExtensionWhitelist(Elsa.Workflows.ActivityExecutionContext,Microsoft.AspNetCore.Http.HttpContext,Microsoft.AspNetCore.Http.IFormFileCollection)
HandleInvalidFileExtensionWhitelistAsync()
ValidateFileExtensionBlacklist(Elsa.Workflows.ActivityExecutionContext,Microsoft.AspNetCore.Http.HttpContext,Microsoft.AspNetCore.Http.IFormFileCollection)
HandleInvalidFileExtensionBlacklistAsync()
ValidateFileMimeTypes(Elsa.Workflows.ActivityExecutionContext,Microsoft.AspNetCore.Http.HttpContext,Microsoft.AspNetCore.Http.IFormFileCollection)
HandleInvalidFileMimeTypesAsync()
HandleInvalidJsonPayloadAsync()
ParseContentAsync()
HasContent(Microsoft.AspNetCore.Http.HttpRequest)
GetBookmarkPayloads(Elsa.Expressions.Models.ExpressionExecutionContext)
GetRouteData(Microsoft.AspNetCore.Http.HttpContext,System.String)