odata / restier Goto Github PK
View Code? Open in Web Editor NEWA turn-key library for building RESTful services
Home Page: http://odata.github.io/RESTier
License: Other
A turn-key library for building RESTful services
Home Page: http://odata.github.io/RESTier
License: Other
ODataDomainController::GetQuery
investigate stable ordering in reference to WCF data services
In ConventionalEntitySetProvider::ExtendModelAsync:
Add new entity type representing entity shape.
For example, we have a the default controller
public class AdventureWorksController : ODataDomainController<AdventureWorksDomain>
{
private AdventureWorks DbContext
{
get { return Domain.Context; }
}
}
And one special controller
public class CustomersController : ODataController
{
private readonly AdventureWorks _context = new AdventureWorks();
[ODataRoute("Customers({key})/EmailAddress")]
public string GetEmailAddress([FromODataUri] int key)
{
return _context.Customers.Single(c => c.CustomerID == key).EmailAddress;
}
}
When try to request ~/Customers(1)/EmailAddress
, it can work correctly but when try to request ~/Customers
, it gets 404 error.User has to add the basic Get
method in the CustomersController
to make it work.
The default controller can automatically handle the basic CRUD operations, these should be "inherited" to the specific controllers. In other word, user don't have to write the logic already implemented in the default controller. In the code above, for example
~/Customers
-- should work directly by AdventureWorksController
~/Customers(1)/EmailAddress
-- should work directly by CustomersController
DomainDataModelReference::EntitySet
In TrippinE2ETestCases
CURDSingleNavigationPropertyAndRef
WebApi doesn't allow return a null entity.
Customer comments on RESTier blog
I see that you are currently using Entity Framework 6.1.1. Do you have plans for EF7 and how you are ready for its core changes (according to http://blogs.msdn.com/b/adonet/archive/2014/10/27/ef7-v1-or-v7.aspx)?For now I briefly inspected the Microsoft.Restier.EntityFramework assembly, and it seems there is not much to change there. Thanks.
In some places the code just throw exception without error message. We'd better add detailed information for those error messages.
Now we have to add specific property routing with code, which is very hard for us to achieve. (P1)
RestierQueryBuilder::GetPathKeyValues
Current parsing implementation does not allow key values to contain commas or equal.
class Domain // TODO: transactions, exception filters
DefaultODataRoutingConvention::SelectAction
implement action selection for $ref, navigation scenarios, etc.
RoleBasedAuthorization::Inspect
// TODO: something other than entity sets
I've posted the following message on OData.org blog:
"We need to allow a single OData Service instance to address multiple connection strings configured in the web config file depending on a key to be included on the URI, like
http://mywebsite.com/myODataService/ConnectionStringA/Products
where ConnectionStringA is the connection name. Does Restier address this need?"
I appreciate Quian Li's reply, and I've tried miself to find how to achieve it.
I'm not familiar with ASP.NET MVC, but I've tried to change the WebApiConfig.cs as follows:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
RegisterM2uSalesV4(config, GlobalConfiguration.DefaultServer);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
public static async void RegisterM2uSalesV4(HttpConfiguration config, HttpServer server)
{
await config.MapODataDomainRoute<M2uSalesV4Controller>(
"M2uSalesV4Api", "api/m2uSalesV4/{company}/",
new ODataDomainBatchHandler(server));
}
}
Then on my controller:
public class M2uSalesV4Controller : ODataDomainController<M2uSalesV4Domain>
{
//private m2uSalesV4OData.Models.m2uSalesv4Entities DbContext
//{
// get { return Domain.Context; }
//}
public Task<System.Net.Http.HttpResponseMessage> Get([FromUri]string company, CancellationToken cancellationToken)
{
return this.Get(cancellationToken);
}
}
and I've checked that the value I've included in the URL I'm using on fiddler for the company gets to this method, but can't find a way to use it to create a DbContext using the company name as the connection string key.
The only way I found, which I'm not proud of was to set a static string property:
public class M2uSalesV4Controller : ODataDomainController<M2uSalesV4Domain>
{
//private m2uSalesV4OData.Models.m2uSalesv4Entities DbContext
//{
// get { return Domain.Context; }
//}
public static string CompanyName = "m2uSalesv4Entities";
public Task<System.Net.Http.HttpResponseMessage> Get([FromUri]string company, CancellationToken cancellationToken)
{
CompanyName = company;
return this.Get(cancellationToken);
}
}
and change the DbContext initializer:
public partial class m2uSalesv4Entities : DbContext
{
}
public m2uSalesv4Entities()
: base("name=" + M2uSalesV4Controller.CompanyName) // "m2uSalesv4Entities"
{
}
and it worked! I can now use:
http://localhost:64068//api/m2uSalesV4/companyA/myTable
http://localhost:64068//api/m2uSalesV4/companyB/myTable
to get values from two databases with the same structure, each with its own connectionstring:
<connectionStrings>
<add name="m2uSalesv4Entities" connectionString="metadata=re ..."/>
<add name="companyA" connectionString="metadata=res://*/Models.m ..."/>
<add name="companyB" connectionString="metadata=res://*/Mode ..."/>
</connectionStrings>
So, I'm looking forward to better alternatives to pick the appropriate connection string .
Customer complains
Why are you using Northwind and not a database compatible with VS 2013? It’s a PITA to have to get Northwind converted to VS 2013 and will stop many people at step one if they try the tutorial.
One better option is to use AdventureWorks or AdventureWorksLT (light version of AdventureWorks). They have better support for higher version of SQL server and can easily download the data files (.md) easily at codeplex and codeplex
It throws saying that sequence contains more than 1 element. Stack is in EntityQueryModelVisitor.BindMemberExpression, in the closure which calls "ps.Single() as IProperty", apparently ps contains more than 1 element.
Repro code is as simple as:
var l5 = ctx.Contacts.Include(o => o.User2).Select(o => new
{
M1 = o.ID,
M2 = o.User2.Name, // This causes InvalidOperationException, while o.User2 ok.
}).ToArray();
Thread safety in core library, e.g. DomainConfiguration.
This needs to define clearly. oCan consider prioritizing EF code-first
Now the question is:
If we must keep EntityResult and EntityCollectionResult, we'd have to implement another etag handler to add the ETag header into response.
check if LinqParameterContainer is necessary
Add IQueryExpressionTranslator - for when the domain types that are different from the data source proxy types.
Implement Target for ValidataionResultDTO. if this is a $batch request return the ContentId "$0" for the target
• Thread safety in core library, e.g. DomainConfiguration.
• Multiple DB schema support for EF provider. (P0)
• Built in property routing. Now we have to add specific property routing with code, which is very hard for us to achieve. (P1)
• OData data source as a provider. (P1)
• A framework to support data mash between multiple data sources. (P2)
• Better expression filter support, provide more meaningful context information via QueryExpressionContext.ModelReference. Now only a limited set of node types have correspondent ModelReferences. (P2)
Support composable function imports, etc. for Model Mapper.
See case FilterBuiltInDateFunctions, when duration is > 1day, the exception is:
Microsoft.OData.Client.DataServiceRequestException : An error occurred while processing this request.
---- Microsoft.OData.Client.DataServiceClientException : {
"error":{
"code":"","message":"An error has occurred.","innererror":{
"message":"An error occurred while updating the entries. See the inner exception for details.","type":"System.Data.Entity.Infrastructure.DbUpdateException","stacktrace":" at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at Microsoft.Restier.EntityFramework.Submit.SubmitExecutor.<ExecuteSubmitAsync>d__0.MoveNext() in d:\\git\\DomainFramework\\src\\Microsoft.Restier.EntityFramework\\Submit\\SubmitExecutor.cs:line 24\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult()\r\n at Microsoft.Restier.Core.Submit.DefaultSubmitHandler.d__2d.MoveNext() in d:\git\DomainFramework\src\Microsoft.Restier.Core\Submit\DefaultSubmitHandler.cs:line 281\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.GetResult()\r\n at Microsoft.Restier.Core.Submit.DefaultSubmitHandler.d__0.MoveNext() in d:\git\DomainFramework\src\Microsoft.Restier.Core\Submit\DefaultSubmitHandler.cs:line 100\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at Microsoft.Restier.Core.Domain.<SubmitAsync>d__19.MoveNext() in d:\\git\\DomainFramework\\src\\Microsoft.Restier.Core\\Domain.cs:line 707\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult()\r\n at Microsoft.Restier.WebApi.ODataDomainController1.<Post>d__e.MoveNext() in d:\\git\\DomainFramework\\src\\Microsoft.Restier.WebApi\\ODataDomainController.cs:line 328\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__3
1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ExceptionFilterResult.d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Web.Http.Controllers.ExceptionFilterResult.d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()","internalexception":{
"message":"An error occurred while updating the entries. See the inner exception for details.","type":"System.Data.Entity.Core.UpdateException","stacktrace":" at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Data.Entity.Core.Objects.ObjectContext.d__3b1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Data.Entity.Core.Objects.ObjectContext.<SaveChangesToStoreAsync>d__37.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<ExecuteAsyncImplementation>d__9
1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Data.Entity.Core.Objects.ObjectContext.d__2f.MoveNext()","internalexception":{
"message":"SqlDbType.Time overflow. Value '1.01:00:00' is out of range. Must be between 00:00:00.0000000 and 23:59:59.9999999.","type":"System.OverflowException","stacktrace":" at System.Data.SqlClient.SqlCommand.b__24(Task1 result)\r\n at System.Threading.Tasks.ContinuationResultTaskFromResultTask
2.InnerInvoke()\r\n at System.Threading.Tasks.Task.Execute()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Data.Entity.Core.Mapping.Update.Internal.DynamicUpdateCommand.d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.d__0.MoveNext()"
}
}
}
}
}
Result StackTrace:
at Microsoft.OData.Client.SaveResult.HandleResponse()
at Microsoft.OData.Client.BaseSaveResult.EndRequest()
at Microsoft.OData.Client.DataServiceContext.SaveChanges(SaveChangesOptions options)
at Microsoft.OData.Client.DataServiceContext.SaveChanges()
at Microsoft.Restier.WebApi.Test.Scenario.TrippinE2ETestCases.FilterBuiltInDateFunctions() in d:\git\DomainFramework\test\ODataEndToEndTests\Microsoft.Restier.WebApi.Test.Scenario\TrippinE2ETestCases.cs:line 277
----- Inner Stack Trace -----
Breeze annotation feature: store-generated, ConcurrencyMode, etc
Figure out a better update baseline experience. Currently the Test Explorer doesn't let you select individual items from the test output.
Need to clarify
Suppose there is code below in NorthwindDomain.cs
private IQueryable<Customer> OnFilterCustomers(IQueryable<Customer> customers)
{
return customers.Where(c => c.CountryRegion == "France");
}
Then in NorthwindController.cs
[ODataRoute("Customers/$count")]
public IHttpActionResult GetCustomersCount()
{
return Ok(DbContext.Customers.Count());
}
still returns the count of customers from all CountryRegion and this cause the inconsistency problem. And user cannot directly using return Ok(OnFilterCustomers(DbContext.Customers).Count());
since the OnFilterCustomers is a private method.
ConventionalChangeSetEntryValidator::ValidateEntityAsync
Soon?
ChangeSetPreparer::FindEntity
There are 2 cases where the entity is not found:
For now, in MapODataDomainRoute, controller.Domain.GetModelAsync is called. This is due to webapi.odata's ODataPathRouteConstraint requires an immutable Edm model, instead of Func<> or a model provider. Therefore, need to create an Edm model when create an OData route.
Properly filter types in RoleBasedAuthorization::IsVisible
Handle other cases: projection operators etc.
Function and action support: being able to incorporate those defined DbContext into EdmModel.
Implement domain versions of all the other EDM interfaces to ensure it is impossible to get elements that are not supposed to be visible.
class Domain // TODO: transactions, exception filters
Support for TimeSpan and DateTime.
Figure out a more appropriate exception
Some of the wiki file names have colons (:
) in them, such as Samples 1: Getting started basic.md
. Colons are illegal characters on NTFS file systems. As a result, the Wiki is unable to be cloned to a Windows machine.
error: Invalid path 'Samples 1: Getting started basic.md'
error: Invalid path 'Samples 2: Getting started - advanced.md'
error: Invalid path 'Samples 3: How to enable multiple controllers.md'
error: Invalid path 'Samples 4: How to add OData operations.md'
I have a few DateTime? propeties in my EF CodeFirst model, but they are all missing from the OData view. Is there a way to bring them in?
Provide more meaningful context information via QueryExpressionContext.ModelReference. Now only a limited set of node types have correspondent ModelReferences.
ODataDomainController::CreateQueryResponse
Support non-Entity ($select/$value) queries
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.