Skip to content

Commit e7a7d5d

Browse files
committed
Add support for Content-Disposition type inline/attachment
1 parent 1937595 commit e7a7d5d

24 files changed

Lines changed: 129 additions & 48 deletions
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Dibix.Http
2+
{
3+
public enum ContentDispositionType
4+
{
5+
None,
6+
Inline,
7+
Attachment
8+
}
9+
}

shared/Http/HttpFileResponseDefinition.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
public sealed class HttpFileResponseDefinition
44
{
55
public bool Cache { get; }
6+
public ContentDispositionType DispositionType { get; }
67

7-
public HttpFileResponseDefinition(bool cache)
8+
public HttpFileResponseDefinition(bool cache, ContentDispositionType dispositionType)
89
{
910
Cache = cache;
11+
DispositionType = dispositionType;
1012
}
1113
}
1214
}

src/Dibix.Http.Host/ModelContextProtocol/McpServerPostConfigureOptions.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,9 @@ public AIFunctionWrapper(AIFunction innerFunction, EndpointDefinition endpoint)
221221
}
222222
}
223223

224-
private sealed class McpResponseDelegator : HttpActionInvokerBase, IHttpActionDelegator, IHttpResponseFormatter<HttpRequestDescriptor>
224+
private sealed class McpResponseDelegator : HttpActionInvokerBase, IHttpActionDelegator
225225
{
226+
private static readonly McpResponseFormatter McpResponseFormatter = new McpResponseFormatter();
226227
private readonly IControllerActivator _controllerActivator;
227228
private readonly IParameterDependencyResolver _parameterDependencyResolver;
228229
private readonly AIFunctionArguments _arguments;
@@ -240,11 +241,14 @@ public async Task Delegate(HttpContext httpContext, IDictionary<string, object>
240241
{
241242
EndpointDefinition endpointDefinition = httpContext.GetEndpointDefinition();
242243
HttpActionDefinition actionDefinition = endpointDefinition.ActionDefinition;
243-
object result = await Invoke(actionDefinition, new HttpRequestDescriptor(httpContext.Request), this, arguments, _controllerActivator, _parameterDependencyResolver, cancellationToken).ConfigureAwait(false);
244+
object result = await Invoke(actionDefinition, new HttpRequestDescriptor(httpContext.Request), McpResponseFormatter, arguments, _controllerActivator, _parameterDependencyResolver, cancellationToken).ConfigureAwait(false);
244245
_arguments.Add(ResultKey, result);
245246
}
247+
}
246248

247-
public Task<object> Format(object result, HttpRequestDescriptor request, HttpActionDefinition action, CancellationToken cancellationToken)
249+
private sealed class McpResponseFormatter : HttpResponseFormatter<HttpRequestDescriptor>
250+
{
251+
public override Task<object> Format(object result, HttpRequestDescriptor request, HttpActionDefinition action, CancellationToken cancellationToken)
248252
{
249253
return Task.FromResult(result);
250254
}

src/Dibix.Http.Host/Runtime/HttpActionDelegator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public async Task Delegate(HttpContext httpContext, IDictionary<string, object>
2222
{
2323
EndpointDefinition endpointDefinition = httpContext.GetEndpointDefinition();
2424
HttpActionDefinition actionDefinition = endpointDefinition.ActionDefinition;
25-
IHttpResponseFormatter<HttpRequestDescriptor> responseFormatter = new HttpResponseFormatter(httpContext.Response);
25+
HttpResponseFormatter<HttpRequestDescriptor> responseFormatter = new HttpResponseFormatter(httpContext.Response);
2626
_ = await Invoke(actionDefinition, new HttpRequestDescriptor(httpContext.Request), responseFormatter, arguments, _controllerActivator, _parameterDependencyResolver, cancellationToken).ConfigureAwait(false);
2727
}
2828
}

src/Dibix.Http.Host/Runtime/HttpResponseFormatter.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66
using Microsoft.AspNetCore.Http;
77
using Microsoft.AspNetCore.Http.Headers;
88
using Microsoft.Net.Http.Headers;
9-
using HttpResponse = Microsoft.AspNetCore.Http.HttpResponse;
109

1110
namespace Dibix.Http.Host
1211
{
13-
internal sealed class HttpResponseFormatter : IHttpResponseFormatter<HttpRequestDescriptor>
12+
internal sealed class HttpResponseFormatter : HttpResponseFormatter<HttpRequestDescriptor>
1413
{
1514
private readonly HttpResponse _response;
1615

@@ -19,11 +18,11 @@ public HttpResponseFormatter(HttpResponse response)
1918
_response = response;
2019
}
2120

22-
public async Task<object?> Format(object? result, HttpRequestDescriptor request, HttpActionDefinition action, CancellationToken cancellationToken)
21+
public override async Task<object?> Format(object? result, HttpRequestDescriptor request, HttpActionDefinition action, CancellationToken cancellationToken)
2322
{
2423
if (action.FileResponse != null)
2524
{
26-
await WriteFileResponse(result, action, cancellationToken).ConfigureAwait(false);
25+
await WriteFileResponse(result, action.FileResponse, cancellationToken).ConfigureAwait(false);
2726
}
2827
else
2928
{
@@ -33,7 +32,7 @@ public HttpResponseFormatter(HttpResponse response)
3332
return null;
3433
}
3534

36-
private async Task WriteFileResponse(object? result, HttpActionDefinition action, CancellationToken cancellationToken)
35+
private async Task WriteFileResponse(object? result, HttpFileResponseDefinition fileResponse, CancellationToken cancellationToken)
3736
{
3837
FileEntity? file = (FileEntity?)result;
3938
if (file == null)
@@ -46,9 +45,9 @@ private async Task WriteFileResponse(object? result, HttpActionDefinition action
4645

4746
ResponseHeaders responseHeaders = _response.GetTypedHeaders();
4847
responseHeaders.ContentType = new MediaTypeHeaderValue(mediaType);
49-
responseHeaders.ContentDisposition = new ContentDispositionHeaderValue("inline") { FileName = file.FileName };
48+
responseHeaders.ContentDisposition = new ContentDispositionHeaderValue(GetContentDispositionType(fileResponse.DispositionType)) { FileName = file.FileName };
5049

51-
if (action.FileResponse.Cache)
50+
if (fileResponse.Cache)
5251
{
5352
DateTime now = DateTime.Now;
5453
TimeSpan year = now.AddYears(1) - now;

src/Dibix.Http.Server.AspNet/HttpActionInvoker.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class HttpActionInvoker : HttpActionInvokerBase
1111
// Uses custom exception handling
1212
public static async Task<object> Invoke(HttpActionDefinition action, HttpRequestMessage request, IDictionary<string, object> arguments, IControllerActivator controllerActivator, IParameterDependencyResolver parameterDependencyResolver, CancellationToken cancellationToken)
1313
{
14-
IHttpResponseFormatter<HttpRequestMessageDescriptor> responseFormatter = new HttpResponseMessageFormatter();
14+
HttpResponseFormatter<HttpRequestMessageDescriptor> responseFormatter = new HttpResponseMessageFormatter();
1515
return await Invoke(action, new HttpRequestMessageDescriptor(request), responseFormatter, arguments, controllerActivator, parameterDependencyResolver, cancellationToken).ConfigureAwait(false);
1616
}
1717
}

src/Dibix.Http.Server.AspNet/HttpResponseMessageFormatter.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@
77

88
namespace Dibix.Http.Server.AspNet
99
{
10-
internal sealed class HttpResponseMessageFormatter : IHttpResponseFormatter<HttpRequestMessageDescriptor>
10+
internal sealed class HttpResponseMessageFormatter : HttpResponseFormatter<HttpRequestMessageDescriptor>
1111
{
12-
public Task<object> Format(object result, HttpRequestMessageDescriptor request, HttpActionDefinition action, CancellationToken cancellationToken) => Task.FromResult(FormatSync(result, request, action));
12+
public override Task<object> Format(object result, HttpRequestMessageDescriptor request, HttpActionDefinition action, CancellationToken cancellationToken) => Task.FromResult(FormatSync(result, request, action));
1313

1414
private static object FormatSync(object result, HttpRequestMessageDescriptor request, HttpActionDefinition action)
1515
{
1616
if (action.FileResponse != null)
1717
{
18-
return CreateFileResponse(result, request, action);
18+
return CreateFileResponse(result, request, action.FileResponse);
1919
}
2020

2121
return result;
2222
}
2323

24-
private static object CreateFileResponse(object result, HttpRequestMessageDescriptor request, HttpActionDefinition action)
24+
private static object CreateFileResponse(object result, HttpRequestMessageDescriptor request, HttpFileResponseDefinition fileResponse)
2525
{
2626
FileEntity file = (FileEntity)result;
2727
if (file == null)
@@ -32,9 +32,9 @@ private static object CreateFileResponse(object result, HttpRequestMessageDescri
3232
HttpResponseMessage response = request.RequestMessage.CreateResponse();
3333
response.Content = new ByteArrayContent(file.Data);
3434
response.Content.Headers.ContentType = new MediaTypeHeaderValue(mediaType);
35-
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline") { FileName = file.FileName };
35+
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue(GetContentDispositionType(fileResponse.DispositionType)) { FileName = file.FileName };
3636

37-
if (action.FileResponse.Cache)
37+
if (fileResponse.Cache)
3838
{
3939
DateTime now = DateTime.Now;
4040
TimeSpan year = now.AddYears(1) - now;

src/Dibix.Http.Server/Dibix.Http.Server.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<Compile Include="..\..\shared\Diagnostics\SourceLocation.cs" Link="Diagnostics\%(Filename)%(Extension)" />
1010
<Compile Include="..\..\shared\Extensions\EnumerableExtensions.cs" Link="Extensions\%(Filename)%(Extension)" />
1111
<Compile Include="..\..\shared\Extensions\ReflectionExtensions.cs" Link="Extensions\%(Filename)%(Extension)" />
12+
<Compile Include="..\..\shared\Http\ContentDispositionType.cs" Link="Model\%(Filename)%(Extension)" />
1213
<Compile Include="..\..\shared\Http\HttpApiMethod.cs" Link="Model\%(Filename)%(Extension)" />
1314
<Compile Include="..\..\shared\Http\HttpErrorResponse.cs" Link="Runtime\%(Filename)%(Extension)" />
1415
<Compile Include="..\..\shared\Http\HttpErrorResponseUtility.cs" Link="Runtime\%(Filename)%(Extension)" />

src/Dibix.Http.Server/Runtime/HttpActionInvokerBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Dibix.Http.Server
77
{
88
public abstract class HttpActionInvokerBase
99
{
10-
protected static async Task<object> Invoke<TRequest>(HttpActionDefinition action, TRequest request, IHttpResponseFormatter<TRequest> responseFormatter, IDictionary<string, object> arguments, IControllerActivator controllerActivator, IParameterDependencyResolver parameterDependencyResolver, CancellationToken cancellationToken) where TRequest : IHttpRequestDescriptor
10+
protected static async Task<object> Invoke<TRequest>(HttpActionDefinition action, TRequest request, HttpResponseFormatter<TRequest> responseFormatter, IDictionary<string, object> arguments, IControllerActivator controllerActivator, IParameterDependencyResolver parameterDependencyResolver, CancellationToken cancellationToken) where TRequest : IHttpRequestDescriptor
1111
{
1212
try
1313
{
@@ -28,7 +28,7 @@ protected static async Task<object> Invoke<TRequest>(HttpActionDefinition action
2828
}
2929
}
3030

31-
private static async Task<object> InvokeCore<TRequest>(HttpActionDefinition action, TRequest request, IHttpResponseFormatter<TRequest> responseFormatter, IDictionary<string, object> arguments, IControllerActivator controllerActivator, IParameterDependencyResolver parameterDependencyResolver, CancellationToken cancellationToken) where TRequest : IHttpRequestDescriptor
31+
private static async Task<object> InvokeCore<TRequest>(HttpActionDefinition action, TRequest request, HttpResponseFormatter<TRequest> responseFormatter, IDictionary<string, object> arguments, IControllerActivator controllerActivator, IParameterDependencyResolver parameterDependencyResolver, CancellationToken cancellationToken) where TRequest : IHttpRequestDescriptor
3232
{
3333
if (action.Authorization.Any())
3434
{
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1-
using System.Threading;
1+
using System;
2+
using System.Threading;
23
using System.Threading.Tasks;
34

45
namespace Dibix.Http.Server
56
{
6-
public interface IHttpResponseFormatter<in TRequest> where TRequest : IHttpRequestDescriptor
7+
public abstract class HttpResponseFormatter<TRequest> where TRequest : IHttpRequestDescriptor
78
{
8-
Task<object> Format(object result, TRequest request, HttpActionDefinition action, CancellationToken cancellationToken);
9+
public abstract Task<object> Format(object result, TRequest request, HttpActionDefinition action, CancellationToken cancellationToken);
10+
11+
protected static string GetContentDispositionType(ContentDispositionType dispositionType) => dispositionType switch
12+
{
13+
ContentDispositionType.Inline => "inline",
14+
ContentDispositionType.Attachment => "attachment",
15+
_ => throw new ArgumentOutOfRangeException(nameof(dispositionType), dispositionType, null)
16+
};
917
}
1018
}

0 commit comments

Comments
 (0)