8000 809 set properties in http request message by james-s-tayler · Pull Request #1001 · reactiveui/refit · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

809 set properties in http request message #1001

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

176 changes: 111 additions & 65 deletions README.md

Large diffs are not rendered by default.

44 changes: 44 additions & 0 deletions Refit.Tests/MultipartTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public interface IRunscopeApi
[Post("/")]
Task<HttpResponseMessage> UploadString([AliasAs("SomeStringAlias")]string someString);

[Multipart]
[Post("/")]
Task<HttpResponseMessage> UploadStringWithHeaderAndRequestProperty([Header("Authorization")] string authorization, [Property("SomeProperty")] string someProperty, [AliasAs("SomeStringAlias")]string someString);

[Multipart]
[Post("/")]
Task<HttpResponseMessage> UploadFileInfo(IEnumerable<FileInfo> fileInfos, FileInfo anotherFile);
Expand Down Expand Up @@ -290,6 +294,46 @@ public async Task MultipartUploadShouldWorkWithString()
var result = await fixture.UploadString(text);
}

[Fact]
public async Task MultipartUploadShouldWorkWithHeaderAndRequestProperty()
{
const string text = "This is random text";
const string someHeader = "someHeader";
const string someProperty = "someProperty";

var handler = new MockHttpMessageHandler
{
RequestAsserts = async message =>
{
Assert.Equal(someHeader, message.Headers.Authorization.ToString());
Assert.Single(message.Properties);
Assert.Equal(someProperty, message.Properties["SomeProperty"]);
},
Asserts = async content =>
{
var parts = content.ToList();

Assert.Single(parts);

Assert.Equal("SomeStringAlias", parts[0].Headers.ContentDisposition.Name);
Assert.Null(parts[0].Headers.ContentDisposition.FileName);
Assert.Equal("text/plain", parts[0].Headers.ContentType.MediaType);
Assert.Equal("utf-8", parts[0].Headers.ContentType.CharSet);
var str = await parts[0].ReadAsStringAsync();
Assert.Equal(text, str);
}
};

var settings = new RefitSettings()
{
HttpMessageHandlerFactory = () => handler
};


var fixture = RestService.For<IRunscopeApi>(BaseAddress, settings);
var result = await fixture.UploadStringWithHeaderAndRequestProperty(someHeader,someProperty, text);
}

[Fact]
public async Task MultipartUploadShouldWorkWithStreamPart()
{
Expand Down
8 changes: 8 additions & 0 deletions Refit.Tests/RefitStubs.Net46.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2635,6 +2635,14 @@ Task<HttpResponseMessage> IRunscopeApi.UploadString(string someString)
return (Task<HttpResponseMessage>)func(Client, arguments);
}

/// <inheritdoc />
Task<HttpResponseMessage> IRunscopeApi.UploadStringWithHeaderAndRequestProperty(string authorization, string someProperty, string someString)
{
var arguments = new object[] { authorization, someProperty, someString };
var func = requestBuilder.BuildRestResultFuncForMethod("UploadStringWithHeaderAndRequestProperty", new Type[] { typeof(string), typeof(string), typeof(string) });
return (Task<HttpResponseMessage>)func(Client, arguments);
}

/// <inheritdoc />
Task<HttpResponseMessage> IRunscopeApi.UploadFileInfo(IEnumerable<FileInfo> fileInfos, FileInfo anotherFile)
{
Expand Down
8 changes: 8 additions & 0 deletions Refit.Tests/RefitStubs.Net5.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2635,6 +2635,14 @@ Task<HttpResponseMessage> IRunscopeApi.UploadString(string someString)
return (Task<HttpResponseMessage>)func(Client, arguments);
}

/// <inheritdoc />
Task<HttpResponseMessage> IRunscopeApi.UploadStringWithHeaderAndRequestProperty(string authorization, string someProperty, string someString)
{
var arguments = new object[] { authorization, someProperty, someString };
var func = requestBuilder.BuildRestResultFuncForMethod("UploadStringWithHeaderAndRequestProperty", new Type[] { typeof(string), typeof(string), typeof(string) });
return (Task<HttpResponseMessage>)func(Client, arguments);
}

/// <inheritdoc />
Task<HttpResponseMessage> IRunscopeApi.UploadFileInfo(IEnumerable<FileInfo> fileInfos, FileInfo anotherFile)
{
Expand Down
8 changes: 8 additions & 0 deletions Refit.Tests/RefitStubs.NetCore2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2635,6 +2635,14 @@ Task<HttpResponseMessage> IRunscopeApi.UploadString(string someString)
return (Task<HttpResponseMessage>)func(Client, arguments);
}

/// <inheritdoc />
Task<HttpResponseMessage> IRunscopeApi.UploadStringWithHeaderAndRequestProperty(string authorization, string someProperty, string someString)
{
var arguments = new object[] { authorization, someProperty, someString };
var func = requestBuilder.BuildRestResultFuncForMethod("UploadStringWithHeaderAndRequestProperty", new Type[] { typeof(string), typeof(string), typeof(string) });
return (Task<HttpResponseMessage>)func(Client, arguments);
}

/// <inheritdoc />
Task<HttpResponseMessage> IRunscopeApi.UploadFileInfo(IEnumerable<FileInfo> fileInfos, FileInfo anotherFile)
{
Expand Down
8 changes: 8 additions & 0 deletions Refit.Tests/RefitStubs.NetCore3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2635,6 +2635,14 @@ Task<HttpResponseMessage> IRunscopeApi.UploadString(string someString)
return (Task<HttpResponseMessage>)func(Client, arguments);
}

/// <inheritdoc />
Task<HttpResponseMessage> IRunscopeApi.UploadStringWithHeaderAndRequestProperty(string authorization, string someProperty, string someString)
{
var arguments = new object[] { authorization, someProperty, someString };
var func = requestBuilder.BuildRestResultFuncForMethod("UploadStringWithHeaderAndRequestProperty", new Type[] { typeof(string), typeof(string), typeof(string) });
return (Task<HttpResponseMessage>)func(Client, arguments);
}

/// <inheritdoc />
Task<HttpResponseMessage> IRunscopeApi.UploadFileInfo(IEnumerable<FileInfo> fileInfos, FileInfo anotherFile)
{
Expand Down
107 changes: 105 additions & 2 deletions Refit.Tests/RequestBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,16 @@ public interface IRestMethodInfoTests
Task<string> FetchSomeStuffWithDynamicHeader(int id, [Header("Authorization")] string authorization);

[Get("/foo")]
Task<string> FetchSomeStuffWithDynamicHeaderQueryParamAndArrayQueryParam([Header("Authorization")] string authorization, int id, [Query(CollectionFormat.Multi)] string[] someArray);
Task<string> FetchSomeStuffWithDynamicHeaderQueryParamAndArrayQueryParam([Header("Authorization")] string authorization, int id, [Query(CollectionFormat.Multi)] string[] someArray, [Property("SomeProperty")] object someValue);

[Get("/foo/bar/{id}")]
Task<string> FetchSomeStuffWithDynamicRequestProperty(int id, [Property("SomeProperty")] object someValue);

[Get("/foo/bar/{id}")]
Task<string> FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey(int id, [Property("SomeProperty")] object someValue1, [Property("SomeProperty")] object someValue2);

[Get("/foo/bar/{id}")]
Task<string> FetchSomeStuffWithDynamicRequestPropertyWithoutKey(int id, [Property] object someValue, [Property("")] object someOtherValue);

[Post("/foo/{id}")]
Task<bool> OhYeahValueTypes(int id, [Body] int whatever);
Expand Down Expand Up @@ -540,6 +549,7 @@ public void DynamicHeadersShouldWork()
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
Assert.Empty(fixture.RequestPropertyParameterMap);
Assert.Null(fixture.BodyParameterInfo);

Assert.Equal("Authorization", fixture.HeaderParameterMap[1]);
Expand All @@ -548,6 +558,50 @@ public void DynamicHeadersShouldWork()
Assert.Equal(2, fixture.Headers.Count);
}

[Fact]
public void DynamicRequestPropertiesShouldWork()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestProperty)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
Assert.Empty(fixture.HeaderParameterMap);
Assert.Null(fixture.BodyParameterInfo);

Assert.Equal("SomeProperty", fixture.RequestPropertyParameterMap[1]);
}

[Fact]
public void DynamicRequestPropertiesWithoutKeysShouldDefaultKeyToParameterName()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestPropertyWithoutKey)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
Assert.Empty(fixture.HeaderParameterMap);
Assert.Null(fixture.BodyParameterInfo);

Assert.Equal("someValue", fixture.RequestPropertyParameterMap[1]);
Assert.Equal("someOtherValue", fixture.RequestPropertyParameterMap[2]);
}

[Fact]
public void DynamicRequestPropertiesWithDuplicateKeysDontBlowUp()
{
var input = typeof(IRestMethodInfoTests);
var fixture = new RestMethodInfo(input, input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey)));
Assert.Equal("id", fixture.ParameterMap[0].Name);
Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type);
Assert.Empty(fixture.QueryParameterMap);
Assert.Empty(fixture.HeaderParameterMap);
Assert.Null(fixture.BodyParameterInfo);

Assert.Equal("SomeProperty", fixture.RequestPropertyParameterMap[1]);
Assert.Equal("SomeProperty", fixture.RequestPropertyParameterMap[2]);
}

[Fact]
public void ValueTypesDontBlowUpBuffered()
{
Expand Down Expand Up @@ -668,6 +722,7 @@ public void ParameterMappingWithHeaderQueryParamAndQueryArrayParam()
Assert.Equal("GET", fixture.HttpMethod.Method);
Assert.Equal(2, fixture.QueryParameterMap.Count);
Assert.Single(fixture.HeaderParameterMap);
Assert.Single(fixture.RequestPropertyParameterMap);
}
}

Expand Down Expand Up @@ -721,6 +776,15 @@ public interface IDummyHttpApi
[Post("/foo/bar/{id}")]
Task<string> PostSomeStuffWithCustomHeader(int id, [Body] object body, [Header("X-Emoji")] string emoji);

[Get("/foo/bar/{id}")]
Task<string> FetchSomeStuffWithDynamicRequestProperty(int id, [Property("SomeProperty")] object someProperty);

[Get("/foo/bar/{id}")]
Task<string> FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey(int id, [Property("SomeProperty")] object someValue1, [Property("SomeProperty")] object someValue2);

[Get("/foo/bar/{id}")]
Task<string> FetchSomeStuffWithDynamicRequestPropertyWithoutKey(int id, [Property] object someValue, [Property("")] object someOtherValue);

[Get("/string")]
Task<string> FetchSomeStuffWithoutFullPath();

Expand Down Expand Up @@ -1434,6 +1498,45 @@ public void AddCustomHeadersToRequestHeadersOnly()
Assert.False(output.Content.Headers.Contains("X-Emoji"), "Content headers include X-Emoji header");
}

[Fact]
public void DynamicRequestPropertiesShouldBeInProperties()
{
var someProperty = new object();
var fixture = new RequestBuilderImplementation<IDummyHttpApi>();
var factory = fixture.BuildRequestFactoryForMethod(nameof(IDummyHttpApi.FetchSomeStuffWithDynamicRequestProperty));
var output = factory(new object[] { 6, someProperty });

Assert.NotEmpty(output.Properties);
Assert.Equal(someProperty, output.Properties["SomeProperty"]);
}

[Fact]
public void DynamicRequestPropertiesWithDefaultKeysShouldBeInProperties()
{
var someProperty = new object();
var someOtherProperty = new object();
var fixture = new RequestBuilderImplementation<IDummyHttpApi>();
var factory = fixture.BuildRequestFactoryForMethod(nameof(IDummyHttpApi.FetchSomeStuffWithDynamicRequestPropertyWithoutKey));
var output = factory(new object[] { 6, someProperty, someOtherProperty });

Assert.NotEmpty(output.Properties);
Assert.Equal(someProperty, output.Properties["someValue"]);
Assert.Equal(someOtherProperty, output.Properties["someOtherValue"]);
}

[Fact]
public void DynamicRequestPropertiesWithDuplicateKeyShouldOverwritePreviousProperty()
{
var someProperty = new object();
var someOtherProperty = new object();
var fixture = new RequestBuilderImplementation<IDummyHttpApi>();
var factory = fixture.BuildRequestFactoryForMethod(nameof(IDummyHttpApi.FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey));
var output = factory(new object[] { 6, someProperty, someOtherProperty });

Assert.Single(output.Properties);
Assert.Equal(someOtherProperty, output.Properties["SomeProperty"]);
}

[Fact]
public void HttpClientShouldPrefixedAbsolutePathToTheRequestUri()
{
Expand Down Expand Up @@ -2094,7 +2197,7 @@ public static Func<object[], TestHttpMessageHandler> RunRequest(this IRequestBui
{

}

return testHttpMessageHandler;
};
}
Expand Down
25 changes: 23 additions & 2 deletions Refit/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public enum BodySerializationMethod
UrlEncoded,

/// <summary>
/// Encodes everything using the ContentSerializer in RefitSettings
/// Encodes everything using the ContentSerializer in RefitSettings
/// </summary>
Serialized
}
Expand Down Expand Up @@ -206,6 +206,27 @@ public HeaderAttribute(string header)
public string Header { get; }
}

/// <summary>
/// Used to store the value in HttpRequestMessage.Properties for further processing in a custom DelegatingHandler.
/// If a string is supplied to the constructor then it will be used as the key in the HttpRequestMessage.Properties dictionary.
/// If no key is specified then the key will be defaulted to the name of the parameter.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type should have doc comments on it and its members

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added some docs to it :)

public class PropertyAttribute : Attribute
{
public PropertyAttribute() { }

public PropertyAttribute(string key)
{
Key = key;
}

/// <summary>
/// Specifies the key under which to store the value on the HttpRequestMessage.Properties dictionary.
/// </summary>
public string Key { get; }
}

[AttributeUsage(AttributeTargets.Parameter)]
public class AuthorizeAttribute : Attribute
{
Expand Down Expand Up @@ -255,7 +276,7 @@ public QueryAttribute(CollectionFormat collectionFormat)
public string Delimiter { get; protected set; } = ".";

/// <summary>
/// Used to customize the name of the encoded value.
/// Used to customize the name of the encoded value.
/// </summary>
/// <remarks>
/// Gets combined with <see cref="Delimiter"/> in the format <code>var name = $"{Prefix}{Delimiter}{originalFieldName}"</code>
Expand Down
16 changes: 15 additions & 1 deletion Refit/RequestBuilderImplementation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ Func<object[], Task<HttpRequestMessage>> BuildRequestFactoryForMethod(RestMethod

return async paramList =>
{
// make sure we strip out any cancelation tokens
// make sure we strip out any cancellation tokens
if (paramsContainsCancellationToken)
{
paramList = paramList.Where(o => o == null || o.GetType() != typeof(CancellationToken)).ToArray();
Expand All @@ -457,6 +457,8 @@ Func<object[], Task<HttpRequestMessage>> BuildRequestFactoryForMethod(RestMethod
var urlTarget = (basePath == "/" ? string.Empty : basePath) + restMethod.RelativePath;
var queryParamsToAdd = new List<KeyValuePair<string, string>>();
var headersToAdd = new Dictionary<string, string>(restMethod.Headers);
var propertiesToAdd = new Dictionary<string, object>();

RestMethodParameterInfo parameterInfo = null;

for (var i = 0; i < paramList.Length; i++)
Expand Down Expand Up @@ -587,6 +589,13 @@ Func<object[], Task<HttpRequestMessage>> BuildRequestFactoryForMethod(RestMethod
headersToAdd["Authorization"] = $"{restMethod.AuthorizeParameterInfo.Item1} {param}";
}

//if property, add to populate into HttpRequestMessage.Properties
if (restMethod.RequestPropertyParameterMap.ContainsKey(i))
{
propertiesToAdd[restMethod.RequestPropertyParameterMap[i]] = param;
isParameterMappedToRequest = true;
}

// ignore nulls and already processed parameters
if (isParameterMappedToRequest || param == null) continue;

Expand Down Expand Up @@ -666,6 +675,11 @@ Func<object[], Task<HttpRequestMessage>> BuildRequestFactoryForMethod(RestMethod
}
}

foreach (var property in propertiesToAdd)
{
ret.Properties[property.Key] = property.Value;
}

// NB: The URI methods in .NET are dumb. Also, we do this
// UriBuilder business so that we preserve any hardcoded query
// parameters as well as add the parameterized ones.
Expand Down
Loading
0