I am having trouble getting OData to work with Asp.Net Web Api when the underlying data is NOT coming from Entity Framework.
I am using the latest OData Nuget package (Microsoft ASP.NET Web API OData 0.2.0-alpha release) but when I attempt to pass an OData query (say $top=10) I receive the error:
The given key was not present in the dictionary
If I don't send an OData query I can call the method just fine. The other methods in the same Web Api project that use Entity Framework work fine with OData queries. The one's that don't work are using Subsonic ORM to query an underlying AS400 data source. It returns an IQueryable. This worked just fine before the VS 2012 and .NET 4.5 RTM was released and OData was moved into a separate package. (i.e. worked with beta and RC versions of VS2012 and .NET 4.5)
Any ideas would be appreciated.
I guess this issue is caused by stable ordering, which doesn't work well with the underlying query provider. Could you put the call stack of the error to confirm it?
One big change with OData query composition in this release is that it ensures stable ordering before taking top items. The reason to do that is user may have random data source which makes return data keep changing.
The way web api odata package does is to add OrderyBy [Keys] query before executing top. Or if there is no key defined in the model (Keys are ID, EntityID, or [Key] attributed property), it will use all the primitive properties in the model to order.
If you can make sure that the data source will always return data with stable ordering, you can turn off this feature by code:
[Queryable(EnsureStableOrdering = false)]
Related
I'm banging my head against the wall with this one.
I'm trying to build an ASP.NET Web API OData service for a customer. The data returned comes from a SQL Server stored procedure that returns data with different structure every time (the columns may change on every execution).
I tried to do it with an entities model but of course - the whole point of EF is a pre-known data model and I found it impossible to get it to work.
I also tried using ADO.NET - get the stored procedure's data using a SqlDataReader and building a DataTable object with the columns (that change every time the stored procedure is executed) but I keep getting configuration errors, http errors and it looks like I'm not getting it right. Getting the stored procedure data worked but something with getting the data to be returned to the OData client doesn't work properly.
Google for several hours and tried several approaches but nothing works. I'm using Visual Studio 2013 (maybe it's too old a version?)
Did anyone succeed in getting variable structured data to be returned from a Web Api OData controller? Any sample projects that show how to do it?
My client is Excel (importing from an OData feed).
I am doing a basic read and write functionality to a IdentityServer4 application using .NET Core 2.0 and have come across an issue. When trying to load clients the ValidateAntiForgeryToken attribute seem to break my update.
I know that EF core does not support lazy loading so we are using an Unit Of Work pattern. I would create separate repositories for Client, ClientScopes, Secrets, etc. and grab the data for each. I will pass in a Func<> to allow filtering when grabbing ClientScopes etc. So a method call would look like this
ClientScopeResitory.GetAll(a => a.Client.Id == id)
which would then access the dbset like this
public IEnumerable GetAll(Func<T, object> predicate == null)
{
return predicate != null ? dbset.Where(predicate) : dbset
}
My issue is when loading the client in my read operation this works just fine. However when using the same code in my update where the ValidateAntiForgeryToken is present it breaks. What happens is in the creation of the repository during the read, the Clients are loaded in with the dbset. However, in the update, the clients are not. When the ValidateAntiForgery attribute is removed. The clients are loaded again and the update works fine. Anyone have any ideas what is going on. I can supply full code upon request. Thanks in advance.
Also, I apologies for any bad grammar or spelling, I wrote this in a hurry
Trying to build a WebAPI 2 / OData v4 service around a typical default Northwind database, using Entity Framework 6.1
My WebApiConfig is unhappy about "complex type relationships":
An exception of type 'System.InvalidOperationException'
occurred in System.Web.OData.dll
but was not handled in user code
Additional information: The complex type 'ODataProductService.Models.Order_Detail'
refers to the entity type 'ODataProductService.Models.Product'
through the property 'Product'.
Obviously, in any given database, these relationships are very likely to occur.
What is the proper way of hanlding this?
Here is how I gat this resolved:
1) added the following statements to my WebApiConfig.cs:
I have made a GitHub repo with a working solution in it:
builder.EntitySet<Customer>("Customers");
builder.EntitySet<Product>("Products");
builder.EntitySet<Order>("Orders").EntityType.HasKey(o => o.OrderID);
builder.EntitySet<Order_Detail>("Order Details").EntityType.HasKey(od => od.OrderID);
builder.EntitySet<CustomerDemographic>("CustomerDemographics").EntityType.HasKey(cd => cd.CustomerTypeID);
I have also made a repo with a working solution:
https://github.com/eugene-goldberg/ODataProductService/
The Readme file pretty much describes what to pay attention to.
You could also use the containment feature of OData V4. Using containment, you can avoid defining an entity set for Order_Detail.
I'm using the latest ASP.Net WebAPI Nightly builds (dated 2013-01-16).
I have a simple EF database first model at the moment that has two entities - Patients and Visits. Each patient can have many visits.
I'd like to be able to query for my list of patients and have the visits entities for each patient returned inline. I know that WebAPI's OData implementation doesn't yet support $expand. I'm hoping that just means that optional client-controlled expansion is not supported and that I can force expansion server-side.
At the moment I'm not getting any of the visits inline.
For example, my PatientController's() Get() method looks like
[Queryable(AllowedQueryOptions=AllowedQueryOptions.Supported)]
public override IQueryable<Patient> Get()
{
var query = this.entities.Patients.Include("Visits");
return query;
}
I've verified that the query executing against my database does indeed include the visit information.
To use a publicly available OData service as an example, if you use the service at http://services.odata.org/OData/OData.svc/, you can get a list of Suppliers. This is http://http://services.odata.org/OData/OData.svc/Suppliers.
You can also ask for a list of suppliers that includes the list of products using http://http://services.odata.org/OData/OData.svc/Suppliers?$expand=Products
Stepping through the ASP.NET code (via the symbols server) I've got to the System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer and can see that it's CreatePropertyBag method, which builds up the list of properties to be serialized, just doesn't include the navigation properties, and they don't seem to be enumerated anywhere else apart from being written out as NavigationLinks.
I'm quite new to the ASP.NET world in general and have spent a week or so getting my head around the way things work (particularly with the changes made to OData at the end of 2012 and further changes made so far in 2013).
I suspect that if the ODataEntityTypeSerializer was to be modified (I'm happy to try) to embed this extra information in the appropriate spot (within each navigation link as an nested inline feed as best I can tell) then I'd be set.
Questions:
Have I overlooked something obvious and there's a flag I can set to turn on this behaviour? I can see why, if such a flag exists, it would be off by default (EF lazy loading and this flag wouldn't get on well)
If #1 is no, is there some other ODataEntityTypeSerializer that I could use? If so, how do I switch to it?
If #2 is no, any pointers for where I should start writing my own? Is there a place I can substitute in my own serializer or do I have to maintain my own fork of ASP.NET's Extensions project (as opposed to the Runtime project)
Thanks very much!
$expand is very high on our list of things to support for OData. But as far as I know, we don't have any flag to turn it on server-side. The formatter doesn't currently allow you to substitute your own serializers either. So I'm afraid your only option in the meantime is to create a fork and add support for $expand. If you manage to get it working, please consider sending a pull request our way:
http://aspnetwebstack.codeplex.com/SourceControl/network
You can try it already in webapi nightly builds.
Here is how to install it with nuget:
http://aspnetwebstack.codeplex.com/wikipage?title=Use%20Nightly%20Builds
For strongly-typed & type-safe solution, I have to do the following step.
Create some Silverlight application.
Binding input control to Linq data class.
Validate data by using rule from attribute of data class.
Send data to server via WCF.
But, I have some question.
How to bind input control with linq data class property?
How to do that with minimal tiers(layers) and minimal required dll(for Silverlight project)?
PS. .Net RIA Service - May Preview isn't my final answer. Because size of all required dll and some generated code.
Thanks,
Well, I'm glad you know that .NET RIA Services will provide all of those things but I understand size is a consideration. Keep in mind though, since it looks like you're considering Silverlight 3 you can use the option to cache the framework assemblies to greatly reduce your Xap size:
http://www.wintellect.com/CS/blogs/jprosise/archive/2009/04/06/silverlight-3-s-new-assembly-caching.aspx
I'm not positive that caching applies to the RIA Services assemblies, but if so it would mean they're downloaded only once.
Assuming that's not what you want there are 2 other options to get data from the Linq classes (I'll assume you mean Entity Framework classes) to the client. The most simple method would be to create your own WCF Service as you've mentioned. That way you write data classes on the server and proxy classes automatically get generated on the client that mimic the server classes. The drawback here is business rules won't be shared between the two. So your data validation attributes will need to be written and enforced on the client & the server separately.
The next option is to use ADO.NET Data Services to move the data from the server to the client. This is a step above the previous option in that you won't have to write a WCF service yourself to host the data; it's generated for you. Of course it requires an extra Dll to be packaged in the Xap.
To answer some of your questions directly:
You can't ever bind an input control directly to a Linq data class. You can only bind controls to the client side proxy classes that are generated by referencing a WCF service (either one you wrote yourself or one provided by ADO.NET Data Services).
If you don't use .NET RIA Services you'll need to create a custom attribute to link to your business rules, then handle events on the data bindings manually to read the attribute and enforce your rules.
Use either of the above options to send data to the server - either your own custom WCF Service or ADO.NET Data Services.
Your final question about binding an input control to a property looks like this:
MyControl.xaml.cs:
public MyControl() {
this.DataContext = new LinqDataClass();
}
MyControl.xaml:
<TextBlock Text={Binding PropertyOnLinqDataClass}/>
Here, LinqDataClass is the client side representation of your server side Linq data class and has a property called PropertyOnLinqDataClass. You'll need to implement the INotifyPropertyChanged interface on the client side to properly support 2 way data binding.