Quantcast
Channel: ASPNETWebStack Issue Tracker Rss Feed
Viewing all 7215 articles
Browse latest View live

Closed Issue: Methods with matrix parameters are not shown in help page [1122]

$
0
0
Our team decided to use standard query parameters in URIs only for sorting and paging and other non filtering actions on resources. For filtering we want to use matrix parameters.
Since it is not guaranteed that query parameters are being cached, matrix parameters should be used where applicable. But when using matrix parameters the help page wont show these requests.

Example:

```
/// <summary>
/// Get customers
/// </summary>
/// <param name="name">Name of the customer.</param>
/// <param name="surname">Surname of the customer.</param>
/// <returns>Returns a list of customers.</returns>
[HttpGet("api/customers;name={name};surname={surname}")]
public IEnumerable<Customer> GetByFilter(string name, string surname)
{
...
}
```

Instead of:
```
/// <summary>
/// Get customers
/// </summary>
/// <param name="name">Name of the customer.</param>
/// <param name="surname">Surname of the customer.</param>
/// <returns>Returns a list of customers.</returns>
[HttpGet("api/customers?name={name?}&surname={surname?}")]
public IEnumerable<Customer> GetByFilter(string name, string surname)
{
...
}
```

Kind regards,
Andy

Commented Unassigned: Set metadata url in ODataMediaTypeFormatter for ODataErrors [1174]

$
0
0
The current code for ODataMediaTypeFormatter contains the following code fragment:

```
// The MetadataDocumentUri is never required for errors. Additionally, it sometimes won't be available
// for errors, such as when routing itself fails. In that case, the route data property is not
// available on the request, and due to a bug with HttpRoute.GetVirtualPath (bug #669) we won't be able
// to generate a metadata link.
if (serializer.ODataPayloadKind != ODataPayloadKind.Error)
{
string metadataLink = urlHelper.ODataLink(new MetadataPathSegment());

if (metadataLink == null)
{
throw new SerializationException(SRResources.UnableToDetermineMetadataUrl);
}

string selectClause = GetSelectClause(Request);
writerSettings.SetMetadataDocumentUri(new Uri(metadataLink), selectClause);
}
```

The if clause is no longer necessary as issue 669 has already been fixed, and it will cause a failure when we update to ODataLib 5.6 so this change has to be made when we upgrade to ODataLib 5.6.
Comments: Doesn't repro on ODataLib 5.6-rc1, however, consider this to simplify the formatter code and keep this bug until RTM to make sure it doesn't repro on RTM either.

Commented Feature: Help Page: Expand documentation [1004]

$
0
0
The "Documentation" property in the ApiDescription and ApiParameterDescription should be expanded to include more XmlComment tags than just "<summary>".
Specifically, it should at least include the <example> tag (with valid sub tags such as <code>), the <exception> tag and the <list> tag.
That way we can actually do the documentation in code and use the HelpPage feature (which is a very good idea) for real world scenarios.

If you feel like it, please also implement these tags <example> and <exception> in the out of the box UI :-)


Morten Petteroe
Comments: And <returns>. Your blog post is great, Yao, but it's also now incompatible with the latest version of the Web API Help pages in Visual Studio 2013 Preview. Some improvements in documentation support out-of-the-box would indeed be welcome.

Edited Issue: Depend upon abstractions instead of concrete implementations for instancing Edm* types [1178]

$
0
0
For example, EdmEntityObjectCollections constructor takes a IList<EdmObject> instead of a List<IEdmObject>. This limit the ability for third parties to provide their own untyped implementation.

Review these problems on the untyped api and modify the API to depend on the abstractions.

Commented Issue: Depend upon abstractions instead of concrete implementations for instancing Edm* types [1178]

$
0
0
For example, EdmEntityObjectCollections constructor takes a IList<EdmObject> instead of a List<IEdmObject>. This limit the ability for third parties to provide their own untyped implementation.

Review these problems on the untyped api and modify the API to depend on the abstractions.
Comments: [Fixed](https://aspnetwebstack.codeplex.com/SourceControl/changeset/769e43f6f5f954987e763ac625b496ab4a4428ac).

Commented Issue: Web API: Improve resolution of ApiController types [1075]

$
0
0
If an assembly A contains ApiControllers and it references another assembly B that does not contain ApiControllers and this assembly B is not found (because it is not installed for example) controller type resolution does not find the ApiControllers in assembly A.

In this case only a 404 status code is returned together with a HttpError message indicating that no matching controller for the specified route could be found. There is no indication __why__ this controller (that actually exists) has not been found.

For a developer who experiences this behaviour (lots of or even all routes return 404) this error is very hard to detect and to analyze. An improvement of either controller type resolution (prefered in my opinion) or at least error reporting or tracing would be very welcome.

Details about this problem are in this Stackoverflow question and its answers:

http://stackoverflow.com/questions/16812995/all-requests-to-asp-net-web-api-return-404-error

I'd like to mention that type resolution for MVC controllers does not suffer from this problem. MVC controllers in assembly A are found, even when assembly B is missing. It would be good in my opinion if controller type resolution in Web API would behave the same way.

Comments: Debugged this further. The issue here is that MVC uses assembly.GetTypes() where as web API uses assembly.GetExportedTypes(). GetExportedTypes() has a different behavior as compared to GetTypes(). GetExportedTypes() throws a FileNotFoundException if it is unable to load dependent assemblies where as GetTypes() throws ReflectionTypeLoadException containing loaded types.

Closed Feature: HttpHeaders collections should benefit from IEnumerable covariance [1127]

$
0
0
Every HttpHeaders collections access from HttpRequestHeaders, HttpResponseHeaders, HttpContentHeaders that takes one of these type parameter:
MediaTypeWithQualityHeaderValue , NameValueWithParametersHeaderValue, TransferCodingWithQualityHeaderValue
should use their less specialized type parameter (without With_X_ in the type name) to benefit from IEnumerable<T> covariance. These collections construction or update should integrate default settings or type casting for Quality or Parameter but their concrete type should stay the more specialized one.
Comments: Hi SebM, I logged this bug in the internal Microsoft bug database so that the team that owns this code can look into addressing this. If you like, you can also open an additional bug via Microsoft Connect (https://connect.microsoft.com/VisualStudio). Thanks, Eilon

Edited Feature: HttpHeaders collections should benefit from IEnumerable covariance [1127]

$
0
0
Every HttpHeaders collections access from HttpRequestHeaders, HttpResponseHeaders, HttpContentHeaders that takes one of these type parameter:
MediaTypeWithQualityHeaderValue , NameValueWithParametersHeaderValue, TransferCodingWithQualityHeaderValue
should use their less specialized type parameter (without With_X_ in the type name) to benefit from IEnumerable<T> covariance. These collections construction or update should integrate default settings or type casting for Quality or Parameter but their concrete type should stay the more specialized one.

Edited Issue: [CORS] The origin URL in CORS in setting should be normalized before comparison [1181]

$
0
0
URL like http://example.com:1234/ and http://example.com:1234 should treated as same origin [1]. It is not true in current implementation. We compare the CORS origin literally without normalizing the string given by user through EnableCors therefore cause CORS rejection which is difficult to find.

The schema of origin is restrictively defined hence we can normalize the user setting. Matching / Comparing origins are defined in RFC6454 [2]

[1] http://tools.ietf.org/html/rfc6454#section-4
[2] http://tools.ietf.org/html/rfc6454#section-5

Edited Issue: [CORS] Consider attaching error message in failed preflight request. [1182]

$
0
0
A failed preflight request returns 400 or 404 with none error message. It is hard to debug from client. CORS Spec does not define what we can put in error preflight response's body [1].

Consider add HttpError message to preflight response. Through which user can control the level of information intent to expose.

[1] http://www.w3.org/TR/cors/#resource-preflight-requests

Commented Issue: HttpActionExecutedContext.Response setter throws exception [1176]

$
0
0
Simple object initializer setting the response property

```
var context = new HttpActionExecutedContext
{
Response = new Http.HttpResponseMessage()
};
```

throws an exception:

```
System.NullReferenceException: Object reference not set to an instance of an object.
at System.Web.Http.Filters.HttpActionExecutedContext.set_Response(HttpResponseMessage value)

```

NuGet package Microsoft.Net.Http ver. __2.2.13__
Comments: Due to there being easy workarounds, and this not being a common scenario, moving to vNext.

Edited Unassigned: [OData] Deserialization should fail when a required field is not present on the Payload [1175]

$
0
0
Having an entity like the following:

```
public class UntypedCustomer
{
public int Id { get; set; }
public string Name { get; set; }
public virtual IList<UntypedOrder> Orders { get; set; }
public virtual IList<UntypedAddress> Addresses { get; set; }
public virtual IList<int> FavoriteNumbers { get; set; }
}
```

and a service that defines an entity set of entities with a required property:
```
ODataModelBuilder builder = new ODataConventionModelBuilder();
var customers = builder.EntitySet<UntypedCustomer>("UntypedCustomers");
customers.EntityType.Property(c => c.Name).IsRequired();
```
when the user sends a payload without the required field:
```
{
"Id": 10,
"Orders": [],
"Addresses": [],
"FavoriteNumbers": []
}
```
the deserialization should fail instead of assigning the default value to the field.

Edited Unassigned: Set metadata url in ODataMediaTypeFormatter for ODataErrors [1174]

$
0
0
The current code for ODataMediaTypeFormatter contains the following code fragment:

```
// The MetadataDocumentUri is never required for errors. Additionally, it sometimes won't be available
// for errors, such as when routing itself fails. In that case, the route data property is not
// available on the request, and due to a bug with HttpRoute.GetVirtualPath (bug #669) we won't be able
// to generate a metadata link.
if (serializer.ODataPayloadKind != ODataPayloadKind.Error)
{
string metadataLink = urlHelper.ODataLink(new MetadataPathSegment());

if (metadataLink == null)
{
throw new SerializationException(SRResources.UnableToDetermineMetadataUrl);
}

string selectClause = GetSelectClause(Request);
writerSettings.SetMetadataDocumentUri(new Uri(metadataLink), selectClause);
}
```

The if clause is no longer necessary as issue 669 has already been fixed, and it will cause a failure when we update to ODataLib 5.6 so this change has to be made when we upgrade to ODataLib 5.6.

Closed Unassigned: In OWIN environment, for some cases 404 response does not have error message in the body [1173]

$
0
0
__Scenario__:
User has a Katana based selfhosted application and is making a request to a non-existing controller

__Issue__:
Response body does not have the detailed error message that Web API usually gives for these kind of scenarios. This would also effect any response headers that might have been added to the response.

__Reason__:
We introduced something called "Soft" 404 to handle scenarios where Web API shouldn't respond directly to the client, but instead invoke any middleware registered 'after' Web API.
In the logic that we currently have, we are eagerly discarding the response body(which would have had the error message that i am expecting) if its a "Soft" 404 and then checking for presence of any registered middleware and invoking it. But if there was no middleware registered, then we should ideally be returing back the correct response, which is including the response body.

__Expected__: {"Message":"No HTTP resource was found that matches the request URI 'http://localhost:14459/api/doesnotexist'.","MessageDetail":"No type was found that matches the controller named 'doesnotexist'."}
__Actual__: No body

__Attached__ a katana selfhost repro.

__HttpMessageHandlerAdapter__ source code(Notice the condition _if (IsSoftNotFound(request, response))_):
```
HttpResponseMessage response = null;
bool callNext = false;
try
{
response = await _messageInvoker.SendAsync(request, owinRequest.CallCancelled);

// Handle null responses
if (response == null)
{
throw Error.InvalidOperation(OwinResources.SendAsync_ReturnedNull);
}

// Handle soft 404s where no route matched - call the next component
if (IsSoftNotFound(request, response))
{
callNext = true;
}
else
{
if (response.Content != null && _bufferPolicySelector.UseBufferedOutputStream(response))
{
response = await BufferResponseBodyAsync(request, response);
}

FixUpContentLengthHeaders(response);
await SendResponseMessageAsync(response, owinResponse);
}
}
finally
{
// Note that the HttpRequestMessage is explicitly NOT disposed. Disposing it would close the input stream
// and prevent cascaded components from accessing it. The server MUST handle any necessary cleanup upon
// request completion.
request.DisposeRequestResources();
if (response != null)
{
response.Dispose();
}
}

// Call the next component if no route matched
if (callNext && Next != null)
{
await Next.Invoke(context);
}
```
Comments: Each piece of middleware is unaware of the other middleware around it - there is no handshaking between them. If there isn't a Web API route that handles the request then Web API gives up and lets the next middleware handle it.

Edited Task: MQ: Update to latest NuGet.targets [1172]

$
0
0
NuGet package restore requires having a checked-in copy of NuGet.targets. We haven't updated ours in a while.

Also, we should examine how the EF team handles interation between NuGet.targets and Runtime.msbuild and see if they have an approach we should follow to keep custom code out of NuGet.targets as much as possible (to make further updates like this one easier).

Edited Task: MQ: Move xUnit build logic out into a NuGet package [1171]

$
0
0
Instead of having a custom, private copy of xUnit build system (test runner) logic (WebStack.xunit.targets), create a standard xUnit targets NuGet package (and share it with other projects such as EF). Also see if the xUnit owners would consider taking ownership of this package.

Note that the EF team is interested in this work as well and might be done in collaboration with them.

Edited Task: MQ: Move StyleCop build logic out into a NuGet package [1170]

$
0
0
Instead of having a custom, private copy of StyleCop build logic (WebStack.StyleCop.targets), create a standard StyleCop targets NuGet package (that could be shared by others projects such as EF). Also see if the StyleCop owners would consider taking ownership of this package.

Edited Issue: PushStreamContent not working under Self hosting server [1169]

$
0
0
The code below it is supposed to write into the console the value of the current datetime every one second. It doesn't. But if the controller is hosted under IIS (instead of under SHS), it works fine.

Test code (console app):
```
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Client {
using System.Web.Http;
using System.Web.Http.SelfHost;

class Program {
static readonly Uri _address = new Uri("http://localhost/ddsrpc/PushContent");

static void RunClient() {
HttpSelfHostServer httpServer = new HttpSelfHostServer(new HttpSelfHostConfiguration("http://localhost"));
httpServer.Configuration.Routes.MapHttpRoute("SseTransport", "ddsrpc/{controller}");
httpServer.OpenAsync().Wait();

HttpClient client = new HttpClient();

HttpRequestMessage request = new HttpRequestMessage {
Method = HttpMethod.Get,
RequestUri = _address,
};

client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ContinueWith(
getTask => {
if (getTask.IsCanceled) {
return;
}
if (getTask.IsFaulted) {
throw getTask.Exception;
}
HttpResponseMessage response = getTask.Result;

response.Content.ReadAsStreamAsync().ContinueWith(
(streamTask) => {
if (streamTask.IsCanceled) {
return;
}
if (streamTask.IsFaulted) {
throw streamTask.Exception;
}

byte[] readBuffer = new byte[512];
ReadResponseStream(streamTask.Result, readBuffer);
});
});
}

private static void ReadResponseStream(Stream rspStream, byte[] readBuffer) {
Task.Factory.FromAsync<byte[], int, int, int>(rspStream.BeginRead, rspStream.EndRead, readBuffer, 0, readBuffer.Length, state: null).ContinueWith(
(readTask) => {
if (readTask.IsCanceled) {
return;
}
if (readTask.IsFaulted) {
throw readTask.Exception;
}

int bytesRead = readTask.Result;
string content = Encoding.UTF8.GetString(readBuffer, 0, bytesRead);
Console.WriteLine("Received: {0}", content);

if (bytesRead != 0) {
ReadResponseStream(rspStream, readBuffer);
}
});
}

static void Main(string[] args) {
RunClient();

Console.WriteLine("Hit ENTER to exit...");
Console.ReadLine();
}
}

public class PushContentController : ApiController {
private static readonly Lazy<Timer> _timer = new Lazy<Timer>(() => new Timer(TimerCallback, null, 0, 1000));
private static readonly ConcurrentDictionary<StreamWriter, StreamWriter> _outputs = new ConcurrentDictionary<StreamWriter, StreamWriter>();

[HttpGet]
public HttpResponseMessage GetUpdates(HttpRequestMessage request) {
Timer t = _timer.Value;
request.Headers.AcceptEncoding.Clear();
HttpResponseMessage response = request.CreateResponse();
response.Content = new PushStreamContent(OnStreamAvailable, "text/plain");
return response;
}

private static void OnStreamAvailable(Stream stream, HttpContent headers, TransportContext context) {
StreamWriter sWriter = new StreamWriter(stream);
_outputs.TryAdd(sWriter, sWriter);
}

private static void TimerCallback(object state) {
foreach (var kvp in _outputs.ToArray()) {
try {
kvp.Value.Write(DateTime.Now);
kvp.Value.Flush();
} catch {
StreamWriter sWriter;
_outputs.TryRemove(kvp.Value, out sWriter);
}
}
}
}
}
```

Commented Issue: PushStreamContent not working under Self hosting server [1169]

$
0
0
The code below it is supposed to write into the console the value of the current datetime every one second. It doesn't. But if the controller is hosted under IIS (instead of under SHS), it works fine.

Test code (console app):
```
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Client {
using System.Web.Http;
using System.Web.Http.SelfHost;

class Program {
static readonly Uri _address = new Uri("http://localhost/ddsrpc/PushContent");

static void RunClient() {
HttpSelfHostServer httpServer = new HttpSelfHostServer(new HttpSelfHostConfiguration("http://localhost"));
httpServer.Configuration.Routes.MapHttpRoute("SseTransport", "ddsrpc/{controller}");
httpServer.OpenAsync().Wait();

HttpClient client = new HttpClient();

HttpRequestMessage request = new HttpRequestMessage {
Method = HttpMethod.Get,
RequestUri = _address,
};

client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ContinueWith(
getTask => {
if (getTask.IsCanceled) {
return;
}
if (getTask.IsFaulted) {
throw getTask.Exception;
}
HttpResponseMessage response = getTask.Result;

response.Content.ReadAsStreamAsync().ContinueWith(
(streamTask) => {
if (streamTask.IsCanceled) {
return;
}
if (streamTask.IsFaulted) {
throw streamTask.Exception;
}

byte[] readBuffer = new byte[512];
ReadResponseStream(streamTask.Result, readBuffer);
});
});
}

private static void ReadResponseStream(Stream rspStream, byte[] readBuffer) {
Task.Factory.FromAsync<byte[], int, int, int>(rspStream.BeginRead, rspStream.EndRead, readBuffer, 0, readBuffer.Length, state: null).ContinueWith(
(readTask) => {
if (readTask.IsCanceled) {
return;
}
if (readTask.IsFaulted) {
throw readTask.Exception;
}

int bytesRead = readTask.Result;
string content = Encoding.UTF8.GetString(readBuffer, 0, bytesRead);
Console.WriteLine("Received: {0}", content);

if (bytesRead != 0) {
ReadResponseStream(rspStream, readBuffer);
}
});
}

static void Main(string[] args) {
RunClient();

Console.WriteLine("Hit ENTER to exit...");
Console.ReadLine();
}
}

public class PushContentController : ApiController {
private static readonly Lazy<Timer> _timer = new Lazy<Timer>(() => new Timer(TimerCallback, null, 0, 1000));
private static readonly ConcurrentDictionary<StreamWriter, StreamWriter> _outputs = new ConcurrentDictionary<StreamWriter, StreamWriter>();

[HttpGet]
public HttpResponseMessage GetUpdates(HttpRequestMessage request) {
Timer t = _timer.Value;
request.Headers.AcceptEncoding.Clear();
HttpResponseMessage response = request.CreateResponse();
response.Content = new PushStreamContent(OnStreamAvailable, "text/plain");
return response;
}

private static void OnStreamAvailable(Stream stream, HttpContent headers, TransportContext context) {
StreamWriter sWriter = new StreamWriter(stream);
_outputs.TryAdd(sWriter, sWriter);
}

private static void TimerCallback(object state) {
foreach (var kvp in _outputs.ToArray()) {
try {
kvp.Value.Write(DateTime.Now);
kvp.Value.Flush();
} catch {
StreamWriter sWriter;
_outputs.TryRemove(kvp.Value, out sWriter);
}
}
}
}
}
```
Comments: Kiran - can you investigate this?

Edited Issue: request.Content.ReadAsMultipartAsync() throws an InvalidOperationException if a part has two Content-Type headers [1168]

$
0
0
If a part of a multipart message contains two Content-Type headers, request.Content.ReadAsMultipartAsync() throws the following:

System.InvalidOperationException: Error parsing MIME multipart body part header byte 115 of data segment System.Byte[]. at System.Net.Http.Formatting.Parsers.MimeMultipartBodyPartParser.<ParseBuffer>d__0.MoveNext() at System.Net.Http.HttpContentMultipartExtensions.MoveNextPart(MultipartAsyncContext context)

I expect a 400 in this case.
Viewing all 7215 articles
Browse latest View live