WCF RIA Services v1 sp1, Composition, validate child entities - silverlight-4.0

I'm using composition attribute. Recently I came into the following blog:
http://brettsam.com/2011/03/25/ria-services-composition-with-entity-framework/
So, I used the approach described in the above blog post to correct entity state of my child entities like the following:
foreach (Child c in this.ChangeSet
.GetAssociatedChanges(currentParent, p => p.Children))
{
ChangeOperation change = this.ChangeSet.GetChangeOperation(c);
switch (change)
{
case ChangeOperation.Delete:
...
case ChangeOperation.Insert:
// This is already done for us.
break;
case ChangeOperation.None:
...
case ChangeOperation.Update:
this.ObjectContext.Children
.AttachAsModified(c, this.ChangeSet.GetOriginal(c));
break;
default:
break;
}
}
I also removed UpdateChild(Child currentChild) method which was generated by default.
Now, the code works and child entities are saved to database as expected. However,
I noticed one problem. My child entity's some properties had custom validation attribute
(inherited from ValidationAttribute class). They were not called at all. This custom
validation attribute is not generated at the silverlight client side, because it uses
some classes which are only available in .NET. but not in silverlight. So, at the
client validation passes, and server-side doesn't validate either. However, if
I add UpdateChild method back to the DomainService, the validation attribute's code runs.
What's wrong here? Can someone explain this?

You should take a look at the EntityGraph
It's more powerful than composition and from my experience it works well - including the kind of validation scenario you have described. In fact you can do way more complicated cross entity validations with the graph.

Related

How to register two controllers same name, different namespace in same ODATA EDM Model?

Objective
The objective is to better understand how to develop modular (plugins by 3rd parties) approach to developing APIs, on top of ASP.NET Core.
To make plugin development easy to pick up it should rely on Conventions where possible, and deliver high value.
OData's queryability and being an Standard remains a compelling improvement to REST, providing a lot of bang for effort.
Issues
OData may be powerful, but the availability of current documentation remains sub par, hence unsure of its limits/capabilities.
Hence questions regarding what options one has to untangling routing issues due to conflicting endpoints from controllers in 3rd party modules.
Specifically:
Q1: Can a single OData EDM model disambiguate between two Controllers with the same name in two different namespaces?
Q2: Can one register an ODataController with a different Route than the ODataController name (eg route Foo points to BarController, when the convention is it would look for a FooController) without breaking default functionality? (eg: $count stops working for me)
Q2b: Even if we take over parsing incoming Uris into its odata path components as well as the logic it uses to find the relevant Controller?
Q3: If it can't, would the more practical approach to loading Plugins be for each Plugin to register its own EDM models?
Q4: Will using multiple EDM models work even if the second plugin/edm model has Controllers that exposes Models that has properties that refer back to Models exposed by Controllers in the base (or another dependency Plugin) EDM model?
Eg: Base EDM exposes Persons and Addresses, and second plugin EDM exposes maybe Customers, which has properties referencing Person and Addresses types, provided by the base EDM?
(I'm guessing it will work, but not 100% sure...anybody see an issue with this?)
Q5: How can one add new EDM models dynamically, resetting the routes?
For example if one uploaded a nuget package that was a plugin, and it contained its own EDM model describing its Models and Controllers...all this happening way after after.Run() was invoked, how can one kick the system in the head to refind/relearn what are valid routes?
Q6: Why is $count only available on ODataControllers that are registered by Convention, but doesn't work on those registered by RouteAttribute?
Background
The latest(?) documentation I found in a blog post here:
https://devblogs.microsoft.com/odata/attribute-routing-in-asp-net-core-odata-8-0-rc/
But it's just a blog post, and a lot remains missing to understand all the pieces and how they fit together.
Process So Far
I'm listing my notes below to help others see better what I am trying, in case someone can see what I am obviously getting wrong.
And if it helps and you want working code, I've uploaded my investigation efforts (actually thrashingArounds):
https://github.com/skysgh/Spikes.AspNetCore.ODataRouting
Setup
The default scenario in OData is to register EDM models with Controller Routes equal to the prefix of the name of the Controller.
Eg:
static string ODataPrefixWithSlash = "api/odata/v{version}/"
class SomeModelController : ODataController {...}
//is registered in an EDM model using convention of matching prefix of controller name:
var builder = new ODataConventionModelBuilder();
//to build a whole model:
builder.EntitySet<SomeModel>("SomeModel"); //This will get found
builder.EntitySet<SomeModel>("Renamed"); //Without further work causes 404 as route string != controller prefix
var edmModelA = builder.Build();
//and the model later registered as the source of OData routing info:
var mvcBuilder = builder.Services
.AddControllers()
.AddOData(
opt => opt.Count().Filter().Expand().Select().OrderBy().SetMaxTop(5)
//Add Module/PluginA Routes:
.AddRouteComponents(AppAPIConstants.ODataPrefixWithSlash,edmModelA);
if one has enabled
builder.Services.AddSwaggerGen();
app.UseODataRouteDebug();
one can navigate to ~odata and see the controller's Endpoints listed as:
~api/odata/v{version}/SomeModel
~api/odata/v{version}/SomeModel/$count <- note, showing for now (will break later...why?!)
Controller Choice Process
An article exists that talks about how routing has been updated in OData v8 RC, relying on RouteAttribute
https://devblogs.microsoft.com/odata/attribute-routing-in-asp-net-core-odata-8-0-rc/
After a lot of messing around, appears one can use a different name but
only IF one starts the route with the same prefix used to register the EDM Model (eg: api/odata/v{version}/
[ODataAttributeRouting]
// Half Works
// because the route starts with the same base as what the model was registered under
// fools it(?) (where?) into accepting it as an Odata controller.
// a) listed in ~/$odata as an odata controller (under api/odata/v{version}
// b) acting as an Odata controller (returning odata wrapper in json)
// c) but no default queryability (doesn't accept or list /$count)
// as the route starts with same prefix
// as Convention used when registereing EDM model
// But $count doesn't work!
[Route(AppAPIConstants.ODataPrefixWithSlash + "Renamed5")]
public class ValuesA5Controller : ODataController{
[EnableQuery(PageSize = 100)]
[HttpGet("")]
[HttpGet("Get")]
public IActionResult Get()
{
return Ok(FakeDataBuilder.Get());
}
}
The above permits registering the ODataController in the EDM model as follows:
builder.EntitySet<SomeModel>("Renamed5");
But it only HALF works.
it is listed as an OData Controller in $odata. ok.
it is acting (mostly) as an ODataController in that it accepts most OData commands $select, $filter, etc.
But it is failing at offering $count for some reason:
~api/odata/v{version}/Renamed5 <- showing, same as it was doing for earlier SomeModelController
~api/odata/v{version}/Renamed5/$count <- not showing, even though endpoint decorated with [EnableQuery].
Options?
Option A: More Route information
I suspect that one could decorate the Get method with more routes to enable $count:
[EnableQuery(PageSize = 100)]
[HttpGet("")]
[HttpGet("Get")]
[HttpGet("$count") ??? <- really???
public IActionResult Get() {....}
Certainly wish to avoid adding more codes as workaround (eg: what was tried here: https://stackoverflow.com/a/73042175/19926885)
but even if either worked, its more code, more sources of errors, etc. to watch out for.
If at all possible I'd like the least code, the most convention, while not locking in controller names.
Option B: Controller Selection process
As I said earlier, I don't know how or where the odata framework is magically matching "SomeModel" to "SomeModelController".
In an article I came across (https://devblogs.microsoft.com/odata/attribute-routing-in-asp-net-core-odata-8-0-rc/)
I saw mention of AttributeRoutingConvention: IODataControllerActionConvention which maybe could be put to use, but the blog post
didn't show when/how it could be registered, or replaced so have not been able to progress in that direction yet.
Also, iterating through registered Services I don't see anything inheriting from IODataControllerActionConvention. What's going on?
What I do see is:
//not sure yet what these do
IODataQueryRequestParser
IODataTemplateTranslator : Microsoft.AspNetCore.OData.Routing.Template.DefaultODataTemplateTranslator
IODataPathTemplateParser : Microsoft.AspNetCore.OData.Routing.Parser.DefaultODataPathTemplateParser`
But I don't have documentation on how they work, what they are for, etc.
Where next?
First of all THANK YOU for taking the time to read this long question!
Second, if you have advice as how I not thinking right as to how to solve the problem, that would help.
Third, if you are able to provide answers to the questions...wow. It's been a while I've looked for answers to this!
Took me a while to recognise the following basic misunderstandings on my part.
OData routing not something else but is an instance of the underlying WebAPI Routing
When one registers an EDM and providing the route prefix ("api/odata/v{version}"), it's just registering "~/api/odata/v{version}/~" as an action/route filter.
If you don't provide a [RouteAttribute] the convention is that it will make it up the Route segment from the Controller name (eg: 'PersonController' means that 'Person' will be used.
If you do provide a [RouteAttribute] on the Controller, you are saying this is the full (not a suffix!) route -- even if you provided a prefix when registering the EDM model.... To underline that point: just because HttpGet(...) acts as a suffix to the Route, doesn't meant the Route does too.
Which means that if it doesn't start with [Route("api/odata/v{version}")] -- maybe is just [Route("Renamed6")] -- it **doesn't match the route prefix used to register the edm model, so won't be handled by the models handler...so all it's doing is acting like all WebAPI controllers are doing and registers another route (whatever you gave), but won't consider it worthy of being OData queryability enabled....
So your route has to be [Route("api/odata/v{version}/Renamed6")].
Other than that, basics are that you'll get it confused if you register two models one with
"api/odata/v{version}", and another with
"api/odata/v{version}/plugin".
The first handler/whatever (i don't know what's behind the scenes here) will probably try to capture requests to plugin and not find a controller called "PluginController". I'm just guessing.
Finally, I think I saw issues with leaving dynamics tokens at the end for some reason. I had to change from using api/odata/PluginA/v{version} to api/odata/v{version}/PluginA . Not clear why.
Admittedly I still need to know a LOT more about the routing mechanism, but for now, this gets me forward again.
PS: Also...use Constants for building route strings. Turns out that Typos can really waste a lot of time :-(

Which layer to handle response code decision in Clean Architecture

Currently implementing Clean Architure using MediatR with
IRequestHandler<IRequest<ResponseMessage>, ResponseMessage>
IRequest<ResponseMessage>
The implementation now separates between business logic layer, infrastructure and controller and they rely on dependency injection and decoupled.
Currently the implementation is in Asp.Net Core and this framework supports response code generation done in controller as example below.
[HttpGet]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> GetObject([FromQuery] int Id)
{
...
return Ok(some_result_to_show); // This generates code 200
}
I wonder where in Clean Architecture layer should translate business rule decisions made into correct response codes and what would be good practice or set methodology doing this adaption.
Seems quick implementation would be still doing it in controller however wonder if this decision belongs to business rules or application business rules and should be handled in different layer before translating into response code in presentation layer.
If then Asp.Net core or MediatR (or any other library) has in-built framework or features to support such design.
One way I found is as below
In the business layer,
RequestMessageValidator : AbstractValidator<RequestMessage>
{
RuleFor(r => r).{ConditionSyntax}().WithErrorCode(ResponseCodeString);
}
Then in the controller,
return StatusCode(
Convert.ToInt32(ValidationResult.Errors[0].ErrorCode),
ValidationResult.Errors[0].ErrorMessage);
It is definitely the application / presentation layer which is MVC or your controllers. I would suggest you to throw specific exceptions that serve only one purpose.
For instance when you query data you will have a request-handler that looks for the data that should be found using a given id (a guid, or whatever). Now that identifier is valid but it is none existence on your database. You don't want to access the httpcontext (even though you could) in your handler because than your businesslogic would be coupled to asp.net. Throw an exception that tells you, that a resource was not found to produce a 404 error response (let's call it ResourceNotFoundException i.e.). For that exception you can then use an exception-filter instead of data-annotation above your controller-endpoints. You can have many exception-filter. Each serves its own purpose.
If you do it like that, your businesslogic will be decoupled from any application / presentation layer and can easily be reused where ever you want.
If you want to see an example of how an exception-filter works, I've created a simple solution for that a while ago. You can find it here.
Not directly related to your question but instead of returning an IActionResult, you could also return a data-transfer-object when you want to send data to the client. It will also produce a Http.OK statuscode.

.net Core 2.0 OData - EnableQuery attribute not allowing operations

I am trying to use Microsoft.AspNetCore.OData, v7.0.0.0-beta1, in a simple project.
I am failing to filter, select, and use top or skip.
Overriding the ValidateQuery of the EnableQueryAttribute, I can successfully perform these type of operations so I believe the library is buggy.
I could not find the right channel to report the issue, can anyone help?
The sample code to reproduce is available here: https://github.com/norcino/AspNetCoreSamples/tree/master/SampleODataApp
The solution to the problem was the actual initialization of the MVC route builder.
Like in the .net framework version it is possible to specify which operation is allowed for OData query. In the example below I am whitelisting everything but you can do a more fine tuning passing an instance of QueryOptionSetting.
app.UseMvc(routeBuilder =>
{
routeBuilder
.Select()
.Expand()
.Filter()
.OrderBy(QueryOptionSetting.Allowed)
.MaxTop(2000)
.Count();
routeBuilder.EnableDependencyInjection();
});
Note that, the attribute [HttpGet, EnableQuery(AllowedOrderByProperties = "Id")], will effectively enforce the order by to the sole Id property specified in the attribute, but first you need to enable all from the configuration.

How is SaveChanges() called in BreezeController?

It appears that all the existing breezejs examples are passing entity models to and from the BreezeController.
But almost all our pages built are using some form of view models. In the days we have no BreezeJs, we retrieve the data (domain model) from a repository to populate (using AutoMapper or manually) a view model, which contains only the necessary data for that view. The WebAPI sends only the view model data over to the browser where we can populate a client-side view model (usually a knockout observable).
When saving data, we collect data from a <form> to populate an input view model, send only that data over to the server, where data in the input view model is mapped to the domain model. The update is saved by calling SaveChanges() on the DbContext entity in the repository.
Now, BreezeJs is to take over all our repository code by creating an EFContextProvider. The examples I have seen usually retrieve the domain model data and then pass it all to the client side.
[HttpGet]
public IQueryable<Item> Items() {
return _contextProvider.Context.Items;
}
It is the client-side javascript's job to build a view model.
Of course it is possible for us to build the view model at the server side:
[HttpGet]
public List<ItemViewModel> Items() {
var items = _contextProvider.Context.Items
.Include("RelatedEntity")
.ToList();
var model = new List<ItemViewModel>();
.... some code to build model from items ....
return model;
}
The benefit is that less data is transferred across the network, and we can do many manipulations on the server side. But I don't know if it is a good practice to modify this BreezeController like that. But at least, it returns data needed to list all the items.
The real trouble came when I tried to POST data back.
In the BreezeJs examples I found, they use a ko.observableArray() to store all the domain model data, let's say vm.items. Then the new record newItem is build by manager.createEntity into a domain model. After validating the data, item.entityAspect.validateEntity(), the newItem is pushed into vm.items and manager.saveChanges() is called, which somehow invokes SaveChanges() on the BreezeController.
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle) {
return _contextProvider.SaveChanges(saveBundle);
}
I find too many things have been taken over! (Laugh at me if you disagree.) My questions are:
Can I just createEntity and then saveChanges?
I only have an empty form to fill in and submit. There is certainly no need to build a whole items array on the client-side.
Can I pass an input view model as a JObject and do some server-side processing before calling _contextProvider.SaveChanges()?
It turns out to be a super long post again. Thank you for reading it all through. Really appreciate it!
Good questions. Unfortunately, our demo code seems to have obscured the real capabilities of Breeze on both client and server. Breeze is not constrained in the ways that your fear.
I don't want to repeat everything that is in our documentation. We really do talk about these issues. We need more examples to be sure.
You are describing a CQRS design. I think it over-complicates most applications. But it's your prerogative.
If you want to send ItemViewModel instead of Item, you can. If you want that to be treated as an entity on the Breeze client - have the EntityManager turn it into a KO observable and manage it in cache, change track it, validate it -, you'll have to provide metadata for it ... either on server or client. That's true for Breeze ... and every other system you can name (Ember, Backbone, etc). Soon we will make it easier to create metadata on the server for an arbitrary CLR model; that may help.
You have complete control over the query on the server, btw, whether Item or ItemViewModel. You don't have to expose an open-ended query for either. You seem to know that by virtue of your 2nd example query.
On to the Command side.
You wrote: "[the examples] use a ko.observableArray() to store all the domain model data, let's say vm.items"
That is not precisely true. The items array that you see in examples exists for presentation. The items array isn't storing anything from a Breeze perspective. In fact, after a query, the entities returned in the query response (if they are entities) are already in the manager's cache no matter what you do with the query result, whether you put them in an array or throw them away. An array plays no role whatsoever in the manager's tracking of the entities.
You wrote: "Can I just createEntity and then saveChanges?"
Of course! The EntityManager.createEntity method puts a new entity in cache. Again, the reason you see it being pushed into the items array is for presentation to the user. That array has no bearing on what the manager will save.
You wrote: "Can I pass an input view model ... and do some server-side processing before calling _contextProvider.SaveChanges()?"
I don't know what you mean by "an input viewmodel". The Breeze EntityManager tracks entities. If your "input viewmodel" is an entity, the EntityManager will track it. If it has changed and you call saveChanges, the manager will send it to the controller's SaveChanges method.
You own the implementation of the controller's SaveChanges method. You can do anything you want with that JObject which is simply a JSON.NET representation of the change-set data. I think you'll benefit from the work that the ContextProvider does to parse that object into a SaveMap. Read the topic on Customizing the EFContextProvider. Most people feel this provides what they need for validating and manipulating the client change-set data before passing those data onto the data access layer ... whether that is EF or something else.
If instead you want to create your own, custom DTO to POST to your own custom controller method ... go right ahead. Don't call EntityManager.saveChanges though. Call EntityManager.getChanges() and manipulate that change array of entities into your DTO. You'll be doing everything by hand. But you can. Personally, I'd have better things to do.

EF4 Self-Tracking entities and WCF serialization creates stack overflow

I try to get above configuration working, but with no luck.
Step 1)
I started a new solution with a WCF Service Application project.
Step 2)
In this project, I added an edmx file and create a very simple model:
Entity Parent with Id and DisplayName
Entity Child with Id and ChildDisplayName
Association from Parent to Child, 1-to-m, resulting in NavigationProperties on both entities.
I generatedthe database without any problems. After generation, I inserted one Parent object with two related Child objects manually to the database.
Step 3)
I added the code generation, using the ADO.NET Self-Tracking Entity Generator.
I know that this should be done in diffrent assemblies, but to make it straight and easy, I put it all to the same project (the WCF project)
Step 4)
I just changed the IService Interface to create a simple get
[OperationContract]
Parent GetRootData(Int32 Id);
In the corresponding implementation, I take an Page object from the context and return it:
using (PpjSteContainer _context = new PpjSteContainer() )
{
return _context.ParentSet.Include("Child").Single(x => x.Id == Id);
}
Problem:
If I now run this project (the Service1.svc is start page), VS2010 automatically generates the test client to invoke the service. But once I invoke the service, I get an StackOverflowException! Debugging on the server side looks ok until it returns the object graph.
If I remove the Include("Child") everything is ok, but of course the Child objects are missing now.
I have no idea what I'm missing. I read a lot of howto's and guides, but all do it the way I did it (at least that's what I think)...
I tried the School example here, but this does not work for me as it seems the database generation and the coding in the example does not match.
So, I would much appreciate if someone could guide me how to make this work.
P.S.
Yes, all Entity-Classes are marked "[DataContract(IsReference = true)]"
Lazy-Loading is set to "false" in the edmx file
Edit:
I changed the WCF to be hosted in a console app and no longer in IIS. Of course then I had to write my own little test client.
Funny enough, now everything's working.
I of course have no idea why, but at least for my testing this is a solution...
Have a look here. Basically you have to make the serializer aware of cycles in the navigation properties.