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

Edited Feature: Provide a way to specify validation settings on MultipartFormDataStreamProvider/MultipartFileStreamProvider, like to limit file size, number of files etc. [921]

$
0
0
Currently a user cannot specify what is the maximum size of a single file that is allowed or combined size of multiple files that are uploaded or restrict the number of files that are uploaded upfront. By upfront I mean that, currently a user would do the following to read a multipart form upload request:

MultipartFormDataStreamProvider provider = await request.Content.ReadAsMultipartAsync<MultipartFormDataStreamProvider>(new MultipartFormDataStreamProvider(@"C:\UploadedFiles"));

After the above statement is executed, it causes all the files to be read and are stored in the UploadedFiles directory.

Only later can the user can go through each file to do his validation. It would be nice if we provide a way for users to specify validation settings regarding this.

Edited Issue: Expose queryable mode option in ODataConvetionModelBuilder [804]

$
0
0
This is useful for unit testing following actions:
IQueryable<string> Get(ODataQueryOptions<Todo> options)

Users have to build options by themselves and in that case, they need a queryable mode model. Otherwise, the model builder won't work for some cases like no-ID entities.

Edited Issue: DependencyScope is disposed before the HttpControllerTracer [768]

$
0
0
### Facts
- I am using AutoFac as IoC container
- I enabled tracing with my custom tracer.
- During the trace operation, I try to get the `DependencyScope` through request.Properties collection.

### Result
At the end of the request (when the response is ready to go out the door), `System.Net.Http.HttpRequestMessageExtensions.DisposeRequestResources` is called to dispose the list of disposables registered inside the `request.Properties["MS_DisposableRequestResources"]`. When tracing is enabled and I am using AutoFac, there are two registered disposables (in the same order as below):

- `Autofac.Integration.WebApi.AutofacWebApiDependencyScope`
- `System.Web.Http.Tracing.Tracers.HttpControllerTracer`

As `DisposeRequestResources` method goes through the list in order, `AutofacWebApiDependencyScope` is disposed before the `HttpControllerTracer`. The funny thing is that `HttpControllerTracer.Dispose` calls the registered tracer to write the End trace and as my trace needs the `DependencyScope`, it blows with the below error since the `DependencyScope` is now disposed:

> {"Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it has already been disposed."}
>
> at Autofac.Core.Lifetime.LifetimeScope.CheckNotDisposed()
> at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
> at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
> at Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable`1 parameters)
> at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType, IEnumerable`1 parameters)
> at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType)
> at Autofac.Integration.WebApi.AutofacWebApiDependencyScope.GetService(Type serviceType)
> at MyProject.HttpRequestMessageExtensions.GetService[TService](HttpRequestMessage request) in e:\Dropbox\Apps\Clients\Serdar\MyProject\src\MyProject.API\Http\HttpRequestMessageExtensions.cs:line 64
> at MyProject.Http.HttpRequestMessageExtensions.GetLoggingService(HttpRequestMessage request) in e:\Dropbox\Apps\Clients\Serdar\MyProject\src\MyProject.API\Http\HttpRequestMessageExtensions.cs:line 33
> at MyProject.API.Tracing.MyProjectTracer.Log(TraceRecord traceRecord) in e:\Dropbox\Apps\Clients\Serdar\MyProject\src\MyProject.API\Tracing\MyProjectTracer.cs:line 23
> at MyProject.API.Tracing.MyProjectTracer.Trace(HttpRequestMessage request, String category, TraceLevel level, Action`1 traceAction) in e:\Dropbox\Apps\Clients\Serdar\MyProject\src\MyProject.API\Tracing\MyProjectTracer.cs:line 17
> at System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEnd(ITraceWriter traceWriter, HttpRequestMessage request, String category, TraceLevel level, String operatorName, String operationName, Action`1 beginTrace, Action execute, Action`1 endTrace, Action`1 errorTrace)
> at System.Web.Http.Tracing.Tracers.HttpControllerTracer.System.IDisposable.Dispose()
> at System.Net.Http.HttpRequestMessageExtensions.DisposeRequestResources(HttpRequestMessage request)

## Suggestion
`System.Net.Http.HttpRequestMessageExtensions.DisposeRequestResources` **should** have a deep knowledge about the `DependencyScope` and **should** dispose it lastly.

### Workaround
There are several workarounds for that (replacing the HttpControllerTracer, etc.) but the one I applied is very dirty. Adding a message handler as the first message handler (so that it runs last (just in case)) and reordering the disposables on the way out:

public class DisposableRequestResourcesReorderHandler : DelegatingHandler {

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {

return base.SendAsync(request, cancellationToken).Finally(() => {

List<IDisposable> disposableResources = request.Properties[HttpPropertyKeys.DisposableRequestResourcesKey] as List<IDisposable>;
if (disposableResources != null && disposableResources.Count > 1) {

// 1-) Get the first one (which I know is AutofacWebApiDependencyScope).
// 2-) Remove it from the list.
// 3-) Push it at the end of the list.

IDisposable dependencyScope = disposableResources[0];
disposableResources.RemoveAt(0);
disposableResources.Add(dependencyScope);
}
}, runSynchronously: true);
}
}

Edited Issue: '/', '\' and ' ' is not handled correctly in string primary key in edit link [498]

$
0
0
'/', '\' can't route to the correct action
' ' will be null value when binding to the id parameter.

Repro code:
public static void RegisterODataRoutes(this HttpConfiguration configuration)
{
// Metadata routes to support $metadata and code generation in the WCF Data Service client.
configuration.Routes.MapHttpRoute(ODataRouteNames.Metadata, "$metadata", new { Controller = "ODataMetadata", Action = "GetMetadata" });
configuration.Routes.MapHttpRoute(ODataRouteNames.ServiceDocument, string.Empty, new { Controller = "ODataMetadata", Action = "GetServiceDocument" });

// Relationship routes (notice the parameters is {type}Id not id, this avoids colliding with GetById(id)).
configuration.Routes.MapHttpRoute(ODataRouteNames.PropertyNavigation, "{controller}({parentId})/{navigationProperty}");

// Route for manipulating links.
//configuration.Routes.MapHttpRoute(ODataRouteNames.Link, "{controller}({id})/$links/Products");
configuration.Routes.MapHttpRoute(ODataRouteNames.Link, "{controller}({id})/$links/{navigationProperty}");

// Routes for urls both producing and handling urls like ~/Product(1), ~/Products() and ~/Products
configuration.Routes.MapHttpRoute("GetByStringId", "{controller}('{id}')");
configuration.Routes.MapHttpRoute(ODataRouteNames.GetById, "{controller}({id})");
configuration.Routes.MapHttpRoute(ODataRouteNames.DefaultWithParentheses, "{controller}()");
configuration.Routes.MapHttpRoute(ODataRouteNames.Default, "{controller}");
}

[EntitySetAttribute("todo")]
[DataServiceKeyAttribute("Name")]
public class Todo
{
[Key]
public string Name { get; set; }
}

public class TodoController : ApiController
{
static TodoController()
{
var todoes = new List<Todo>();
foreach (var c in "/ \\")
{
todoes.Add(new Todo()
{
Name = c.ToString()
});
}
Todoes = todoes;
}

public static IEnumerable<Todo> Todoes { get; set; }

public IEnumerable<Todo> Get()
{
return Todoes;
}

public Todo GetById(string id)
{
return Todoes.FirstOrDefault(t => t.Name == id);
}

[AcceptVerbs("Merge")]
public Todo Put(string id, Todo todo)
{
todo = Todoes.FirstOrDefault(t => t.Name == id);
return todo;
}
}

Client code:
[Fact]
public void TestSpecialCharacters()
{
DataServiceContext ctx = new DataServiceContext(new Uri(this.BaseAddress));
var todoes = ctx.CreateQuery<Todo>("todo").ToList();

foreach (var todo in todoes)
{
Uri selfLink;
Assert.True(ctx.TryGetUri(todo, out selfLink));
Console.WriteLine(selfLink);

ctx.UpdateObject(todo);

var response = ctx.SaveChanges().Single();

Assert.Equal(200, response.StatusCode);
}
}

Closed Issue: Breaking razor change reports incorrect error, "} expected" [390]

$
0
0
in v1, the following was legal (in that: it worked) in razor, in a code region:

string foo = @Some.Complex.Expression;

obviously the @ is redundant, but: it worked. When upgrading to v2, it errors (which I could respect), but **in the wrong way**. It *should* say something about the @ being illegal in that syntax; instead, this can manifest in "} expected", especially if this is inside an if-block etc. The correct code is of course:

string foo = Some.Complex.Expression;

but the error message "} expected" makes the developer look for the wrong thing.
Comments: Hey Marc, This is a really great comment. We discovered this a while ago as well, and it's unfortunate that this doesn't work, as the @ is a valid C#, but it collides with the Razor @. Your suggestion is correct, and the code should be written without the @. However fixing the parser is rather complex, and we are concerned with introducing regressions for this case. So we decided not to fix. If you feel strongly that this is critical please let us know. Thanks The MVC team.

Edited Issue: HttpResponseException doesn't work in custom IHttpRoute implementation [387]

$
0
0
I have a custom IHttpRoute implementation for doing some custom routing. I want to throw a 400 (bad request) sometimes. I tried to do a "throw new HttpResponseException()" in my code but the client always receives a 500.

Edited Issue: Adding support for collection of simple types on the default action selector. [322]

$
0
0
Currently if we have the following action, the request below would fail with "Multiple actions were found..." error because the parameters are not simple types so they're not used for disambiguation by the default action selector. For vnext, we can consider adding special support for collection of simple types.

public string Get([FromUri] IEnumerable<long> id)
public string Get([FromUri] IEnumerable<long> campaignId)

Request: GET /api/Test?id=1&id=2&id=3

Commented Issue: Make User property of ApiController testable [971]

$
0
0
Make the User property of ApiController virtual so that it can be mocked or add a setter so that it can be setup for test.
Comments: We should consider making all the properties on ApiController virtual. That would be a super quick fix that would allow proper mocking.

Edited Issue: [AttributeRouting]Action having multiple attributes should have appropriate method constraints for corresponding route template [969]

$
0
0

For the following action:
```
[HttpPost("api/values/path1")]
[HttpGet("api/values/path2")]
public void DoSomething()
{
}

```

Currently the routes in the collection are like following:

RouteTemplate:
'api/values/path1' (note: __path1__)
Defaults:
Key:controller, Value:Values
Key:action, Value:DoSomething
Constraints:
Key:httpMethod, Value: __POST, GET__


RouteTemplate:
'api/values/path2' (note: __path2__)
Defaults:
Key:controller, Value:Values
Key:action, Value:DoSomething
Constraints:
Key:httpMethod, Value: __POST, GET__


While fixing this issue, also look into the following scenario:

For the following action:
```
[HttpGet("api/values/path1")]
[HttpGet("api/values/path2")]
public void DoSomething()
{
}
```

Currently following is the route information:

RouteTemplate: 'api/values/path1'
Defaults:
Key:controller, Value:Values
Key:action, Value:DoSomething
Constraints:
Key:httpMethod, Value: __GET, GET__

RouteTemplate: 'api/values/path2'
Defaults:
Key:controller, Value:Values
Key:action, Value:DoSomething
Constraints:
Key:httpMethod, Value: __GET, GET__

Edited Issue: Provide an easier extension to supply route specific message handler [886]

$
0
0
Currently a user has to do the following for inserting a per-route message handler. Provide an easier extension where we wire up the default HttpControllerDispatcher ourselves.

```
config.Routes.MapODataRoute(
routeName: "OData",
routePrefix: null,
model: ModelBuilder.GetEdmModel(), handler: HttpClientFactory.CreatePipeline(new HttpControllerDispatcher(config),
new DelegatingHandler[] { new ExcelCompliantMessageHandler() }));
```

Edited Issue: PushStreamContent is swallowing exception [910]

$
0
0
I am using HttpClient and PushStreamContent to upload 1GB of data. I noticed that if I do _not_ use the try-catch below, I am not seeing any exception thrown. Actually there is an out-of-memory exception being thrown by HttpClient here. Re-enable the commented try-catch block and you should see the problem.

__Attached__ a standalone repro.

```
// 1. PushStreamContent (this is not seekable)
request.Content = new PushStreamContent((requestStream, content, transportContext) =>
{
//try
//{
using (requestStream)
{
for (long i = 0; i < iterations; i++)
{
// writing chunks of 1KB to the wire
requestStream.Write(buffer, 0, buffer.Length);
requestStream.Flush();
}

if (remainingBytes > 0)
{
requestStream.Write(buffer, 0, (int)remainingBytes);
requestStream.Flush();
}
}
//}
//catch (Exception ex) //NOTE: without this try-catch block, i do not see any error thrown
//{
// Console.WriteLine("Exception occurred while writing to request stream:\n{0}\n", ex.ToString());
//}
});
```

Commented Issue: PushStreamContent is swallowing exception [910]

$
0
0
I am using HttpClient and PushStreamContent to upload 1GB of data. I noticed that if I do _not_ use the try-catch below, I am not seeing any exception thrown. Actually there is an out-of-memory exception being thrown by HttpClient here. Re-enable the commented try-catch block and you should see the problem.

__Attached__ a standalone repro.

```
// 1. PushStreamContent (this is not seekable)
request.Content = new PushStreamContent((requestStream, content, transportContext) =>
{
//try
//{
using (requestStream)
{
for (long i = 0; i < iterations; i++)
{
// writing chunks of 1KB to the wire
requestStream.Write(buffer, 0, buffer.Length);
requestStream.Flush();
}

if (remainingBytes > 0)
{
requestStream.Write(buffer, 0, (int)remainingBytes);
requestStream.Flush();
}
}
//}
//catch (Exception ex) //NOTE: without this try-catch block, i do not see any error thrown
//{
// Console.WriteLine("Exception occurred while writing to request stream:\n{0}\n", ex.ToString());
//}
});
```
Comments: Some notes from Kiran's investigation: > Yeah, right, the data is getting buffered at the client before its being sent and since the user was sending huge files, they were seeing OutOfMemoryException. > >We came to know later that HttpClient is buffering here because when PushStreamContent is used we do not set Content-Length header and expect the content to be sent in chunked transfer encoding, but it seems HttpClient was designed this way as many servers do not accept chunked encoded data. So, we addressed the user’s issue by explicitly setting the ‘request.Headers.TransferEncodingChunked=true’. > >I do not think this bug is super important, but it did take me some time to figure out the issue (as I wasn’t seeing the exception that the client was reporting). That said, I think the user’s usage here is incorrect as I think they should be using the StreamContent rather than PushStreamContent.

Edited Issue: ModelBinder errors (parse) for required action parameters result in the action not getting executed. [942]

$
0
0
```
public class CustomersController : ApiController
{
public Customer GetCustomer(int key)
{
return null;
}
}
```

Use the url http://localhost/MyTypes/2886753098675309

This should fail to parse as 2886753098675309 is too big for an int.

Expectation: The controller action gets invoked, with model state errors - or at least a better error message that contains the model state errors.

Result:

```
{
"Message": "The request is invalid.",
"MessageDetail": "The parameters dictionary contains a null entry for parameter 'key' of non-nullable type 'System.Int32' for method 'RuntimeTests.Customer GetCustomer(Int32)' in 'RuntimeTests.CustomersController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}
```

See http://aspnetwebstack.codeplex.com/workitem/936 for how this makes OData scenarios harder.

Closed Issue: ModelBinder errors (parse) for required action parameters result in the action not getting executed. [942]

$
0
0
```
public class CustomersController : ApiController
{
public Customer GetCustomer(int key)
{
return null;
}
}
```

Use the url http://localhost/MyTypes/2886753098675309

This should fail to parse as 2886753098675309 is too big for an int.

Expectation: The controller action gets invoked, with model state errors - or at least a better error message that contains the model state errors.

Result:

```
{
"Message": "The request is invalid.",
"MessageDetail": "The parameters dictionary contains a null entry for parameter 'key' of non-nullable type 'System.Int32' for method 'RuntimeTests.Customer GetCustomer(Int32)' in 'RuntimeTests.CustomersController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}
```

See http://aspnetwebstack.codeplex.com/workitem/936 for how this makes OData scenarios harder.
Comments: Because the "key" parameter is a regular int, it is a ValueType, which means that it must have a valid value in order to be called. To get the action to be called you can use a nullable int ("int?") and then the action should be dispatched and ModelState will contain the error.

Edited Feature: Dynamic views location [981]

$
0
0
Although you can add new view locations using the various format properties (ViewLocationFormats, PartialViewLocationFormats, etc.), there is no way to implement locations that vary on dynamic values other than controller, action and area. The String.Format call is internal, and the cache key used is based on those three values only.

Edited Feature: Global error handler for Web API [1001]

$
0
0
If my Web API application is going to return an error to a client, I want to know about it.

I want to set up something like ELMAH to notify me when the problem occurs, and I want full details of the error, including exception stack trace, logged on the server.

In MVC, the __Application_Error__ event is how you achive this, but in Web Api this event often isn't triggered because exceptions are converted into **HttpResponseMessage**s higher in the call stack, and because some error conditions create a **HttpResponseMessage** directly without using an exception. One source of this is __HttpControllerDispatcher.SendAsync__, which catches all exceptions and turns them into error responses, discarding the exception information.

Here are some examples of exceptions that I am interested in handling:

* Exceptions thrown from action methods and action filters
* Exceptions thrown when creating a controller instance
* Exceptions due to routing errors, bad requests, authentication problems, and invalid OData queries
* Exceptions thrown when an IQueryable returned by an action method fails to execute
* Exceptions thrown by custom message handlers and formatters

When I started using Web API, I was surprised when my __Application_Error__ handler did not pick up an action method exception. I added a global __ExceptionFilterAttribute__ to take care of that, but then found several other categories of errors that could be returned to the client and still leave silence in the server logs.

In a production environment, relying on clients to report errors and having no error information available on the server will make diagnosing problems reactive and difficult.

Please provide a global error handling event for Web API, so that error details can be logged and notifications sent. The event should provide access to unhandled exceptions and non-success **HttpResponseException**s and **HttpResponseMessage**s. In the case of **HttpError** objects created from an exception, the exception details should be retained for the error handling event.

Commented Feature: Global error handler for Web API [1001]

$
0
0
If my Web API application is going to return an error to a client, I want to know about it.

I want to set up something like ELMAH to notify me when the problem occurs, and I want full details of the error, including exception stack trace, logged on the server.

In MVC, the __Application_Error__ event is how you achive this, but in Web Api this event often isn't triggered because exceptions are converted into **HttpResponseMessage**s higher in the call stack, and because some error conditions create a **HttpResponseMessage** directly without using an exception. One source of this is __HttpControllerDispatcher.SendAsync__, which catches all exceptions and turns them into error responses, discarding the exception information.

Here are some examples of exceptions that I am interested in handling:

* Exceptions thrown from action methods and action filters
* Exceptions thrown when creating a controller instance
* Exceptions due to routing errors, bad requests, authentication problems, and invalid OData queries
* Exceptions thrown when an IQueryable returned by an action method fails to execute
* Exceptions thrown by custom message handlers and formatters

When I started using Web API, I was surprised when my __Application_Error__ handler did not pick up an action method exception. I added a global __ExceptionFilterAttribute__ to take care of that, but then found several other categories of errors that could be returned to the client and still leave silence in the server logs.

In a production environment, relying on clients to report errors and having no error information available on the server will make diagnosing problems reactive and difficult.

Please provide a global error handling event for Web API, so that error details can be logged and notifications sent. The event should provide access to unhandled exceptions and non-success **HttpResponseException**s and **HttpResponseMessage**s. In the case of **HttpError** objects created from an exception, the exception details should be retained for the error handling event.
Comments: Youssef, if you have a chance to take a look at this that would be great. Even if there's no straightforward fix we would like to work with UE on this and produce guidance on how to handle errors in a Web API service, including all the various places where errors can happen. If we end up just producing guidance, that's OK - we can take this as a vNext feature for any actual implementation work that we'd want to consider.

Edited 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

Edited Feature: Consider improving the experience for accessing properties in EdmObject [1023]

$
0
0
Before the changes introduced by $select and $expand, defining custom odata links was reasonably straightforward using EntityInstanceContext.EntityInstance as in the following snippet.

```
eic =>
{
DerivedEntity entity = eic.EntityInstance as DerivedEntity;
if (entity == null || entity.Id % 2 == 1)
{
return null;
}
else
{
IList<ODataPathSegment> segments = new List<ODataPathSegment>();
segments.Add(new EntitySetPathSegment(eic.EntitySet));
segments.Add(new KeyValuePathSegment(entity.Id.ToString()));
segments.Add(new CastPathSegment(entity.GetType().FullName));
segments.Add(new ActionPathSegment("TransientActionDerivedType"));
string link = eic.Url.ODataLink("Actions", eic.Request.GetODataPathHandler(), segments);
return new Uri(link);
}
};
```

With the changes introduced in EntityInstanceContext by $select and $expand, the user is forced to access the EdmObject property, which is basically a Dictionary, instead of the EntityInstance property that now is null. The following is a sample of the new code that the user needs to write.

```
eic =>
{
IEdmEntityType derivedType = eic.EdmModel.FindType(typeof(DerivedEntity).FullName) as IEdmEntityType;
object id;
eic.EdmObject.TryGetValue("Id", out id);
if (!eic.EntityType.IsOrInheritsFrom(derivedType) || (int)id % 2 == 1)
{
return null;
}
else
{
IList<ODataPathSegment> segments = new List<ODataPathSegment>();
segments.Add(new EntitySetPathSegment(eic.EntitySet));
segments.Add(new KeyValuePathSegment(id.ToString()));
segments.Add(new CastPathSegment(derivedType.FullName()));
segments.Add(new ActionPathSegment("TransientActionDerivedType"));
string link = eic.Url.ODataLink("Actions", eic.Request.GetODataPathHandler(), segments);
return new Uri(link);
}
};
```
Place special attention at:
__object id;
eic.EdmObject.TryGetValue("Id", out id);__

EdmObject could provide a safer, typed way to access the elements in it as $select doesn't perform any kind of renaming. For example:

eic.EdmObject.GetPropertyAs<EntityType>(x => x.Property);

This way, the custom link generation would be much more similar to what it used to be.


Commented Feature: Consider improving the experience for accessing properties in EdmObject [1023]

$
0
0
Before the changes introduced by $select and $expand, defining custom odata links was reasonably straightforward using EntityInstanceContext.EntityInstance as in the following snippet.

```
eic =>
{
DerivedEntity entity = eic.EntityInstance as DerivedEntity;
if (entity == null || entity.Id % 2 == 1)
{
return null;
}
else
{
IList<ODataPathSegment> segments = new List<ODataPathSegment>();
segments.Add(new EntitySetPathSegment(eic.EntitySet));
segments.Add(new KeyValuePathSegment(entity.Id.ToString()));
segments.Add(new CastPathSegment(entity.GetType().FullName));
segments.Add(new ActionPathSegment("TransientActionDerivedType"));
string link = eic.Url.ODataLink("Actions", eic.Request.GetODataPathHandler(), segments);
return new Uri(link);
}
};
```

With the changes introduced in EntityInstanceContext by $select and $expand, the user is forced to access the EdmObject property, which is basically a Dictionary, instead of the EntityInstance property that now is null. The following is a sample of the new code that the user needs to write.

```
eic =>
{
IEdmEntityType derivedType = eic.EdmModel.FindType(typeof(DerivedEntity).FullName) as IEdmEntityType;
object id;
eic.EdmObject.TryGetValue("Id", out id);
if (!eic.EntityType.IsOrInheritsFrom(derivedType) || (int)id % 2 == 1)
{
return null;
}
else
{
IList<ODataPathSegment> segments = new List<ODataPathSegment>();
segments.Add(new EntitySetPathSegment(eic.EntitySet));
segments.Add(new KeyValuePathSegment(id.ToString()));
segments.Add(new CastPathSegment(derivedType.FullName()));
segments.Add(new ActionPathSegment("TransientActionDerivedType"));
string link = eic.Url.ODataLink("Actions", eic.Request.GetODataPathHandler(), segments);
return new Uri(link);
}
};
```
Place special attention at:
__object id;
eic.EdmObject.TryGetValue("Id", out id);__

EdmObject could provide a safer, typed way to access the elements in it as $select doesn't perform any kind of renaming. For example:

eic.EdmObject.GetPropertyAs<EntityType>(x => x.Property);

This way, the custom link generation would be much more similar to what it used to be.


Comments: RaghuRam, can you take a look and see if three is anything we need to do here to make the experience for $select and $expand any better?
Viewing all 7215 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>