I'm attempting to create an instance of an entity and two child entities at the same time.
If I post the following JSON to the /user_objects resource it happily creates the parent user_object entity and the linked User_object_attribute entity. The only problem is that I can't seem to expand the result set to include the new user_object_attribute so I effectively have the most uptodate version of the user_object but I have to then go and read from the OData service i.e. another server hit in order to retrieve the user_object_attributes.
Upon returning I have the id that would go neatly into the child user_object_attribute object but what if the child had a further server-side generated field like created_date? Then I still have to hit the OData repo again?
I've tried the correct $expand query ?$expand=user_objects_attributes and while the creation succeeds I still am not returned the expanded result set.
Would anyone have any idea if this is possible? Or is it a case that it isn't because hte only way to do it would be to return all the child user_object_attributes?
{
"annotator_id":1,
"content_type":"content_type",
"created_date":"2013-02-15T17:20:09.191",
"guid":"GUID",
"size_kb":100,
"title":"Title",
"updated_date":null,
"url":"URL",
"user_object_id":0,
"user_objects_attributes":[
{
"attribute_id":0,
"name":"name191",
"user_object_id":0,
"value":"value191"
}
]
}
Thanks,
Mark.
Looking at the OData V3 specification here:
In version 1.0 and version 2.0, if the insert succeeds in full, the
server MUST return a response with a 201 (Created) status code and a
response body that conforms to the syntax specified in InsertEntity
Request (section 2.2.7.1.1). The response body MUST contain the values
of the inserted resource after the server has executed all its
server-specific data processing rules (validation, and so on). The
server MAY alter the values of the resource received from the client
before the resource is inserted on the server.
In version 3.0, the response MAY have a 204 status code, as specified
in [RFC2616], based on the client preference (see Prefer (section
2.2.5.9)) on the InsertEntity Request.
Not super clear what a server should do... return just the top level created entity, or that entity and all of it's expanded links as well.
I'm not surprised that $expand would have no effect on POST (or any CUD requests). WCF DS probably ignores it if it isn't a query. And by the spec, this is probably correct.
Quite frankly, I think with WCF DS Server you can't get anything else back. In V3 you either get a 201 with your entity (only), or a 204 no content if you specify the header saying that you want no content.
Whether that is OData compliant or not... not totally sure :-). Regardless, I don't think you can get what you want on the WCF DS stack at this point in time.
I was able to return navigation properties after a POST to create a new entity using OData v4's $expand query option without issues.
Make sure your method is decorated with [EnableQuery] and you call Include with the name of the navigation property.
For example:
[EnableQuery]
public IHttpActionResult Post(user_object user)
{
if (!this.ModelState.IsValid)
{
return this.BadRequest(this.ModelState);
}
this.db.user_objects.Add(user);
this.db.SaveChanges();
user = this.db.user_objects.Include("user_objects_attributes").Single(x => x.user_object_id == user.user_object_id));
return this.Created(user);
}
The POST URL query string should include ?$expand=user_objects_attributes.
Also see:
https://github.com/OData/WebApi/issues/356
Related
I am using an OData model for a table, but the data is not loaded. The OData model is created by constructor in the following way:
new sap.ui.model.odata.ODataModel("/XMII/IlluminatorOData/QueryTemplate?QueryTemplate=testTemplate", {annotationURI: "/XMII/IlluminatorOData/$metadata"});
I cannot use the root URI of the OData service, because I need to specify a QueryTemplate.
After setting the model to the table, bindRows method is invoked with parameter "/Row".
table.bindRows("/Row")
The template for a column is a TextField.
template: new sap.ui.commons.TextField().bindProperty("value", "PROJECT")
The data is not shown and not even requested. Only metadata is fetched. What am I doing wrong with OData model? If I fetch the URI which was passed to the model with a get request, content is available.
Are you sure the URL is right?
Shouldn't it be something like "/XMII/IlluminatorOData/?QueryTemplate=testTemplate"
The ODataModel needs to load the metadata in order to work, this means it fetches it from "[ServiceUrl]$metadata", which would be "/XMII/IlluminatorOData/QueryTemplate/$metadata" in your case. But you also use the metadata as annotation source - there you use a different URL, so I guess you first one is wrong...?
My entity name is "Products" but in my WebApi the route is defined as "GetProducts" so in default it will query against /api/Products? instead of /api/GetProducts, is there any way to specify where it should fetch the data from the server if it can't find what i want in the cache.
So far i got this
manager.fetchEntityByKey("Products", productId, true)
.then(fetchSucceeded)
.fail(queryFailed);
This will call http://localhost:1990/breeze/Products?$filter=Id%20eq%201
But i want it to call http://localhost:1990/breeze/GetProducts?$filter=Id%20eq%201 instead
There's also another option to specify this on the server. With WebApi 2, you can use the RouteAttribute on your controller action to customize the routing.
See http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2
EDIT:
On the client, the Breeze EntityType has a property called defaultResourceName which you can modify as well to tell Breeze which default resource name to use if only an entity type name is specified.
var productType = metadataStore.getEntityType('Products');
productType.defaultResourceName = 'GetProducts';
//Will create fetch request to breeze/GetProducts
manager.fetchEntityByKey('Products', productId);
You can change entity's default resourceName(that hits the breeze webapi method name) with
manager.metadataStore.setEntityTypeForResourceName("GetProducts", "Product")
But be sure the code above is executed when promise of manager.fetchMetadata() is resolved:
manager.fetchMetadata().then(function(){
manager.metadataStore.setEntityTypeForResourceName(...);
})
If setEntityTypeForResourceName is called before metadata has loaded you will get an error, i.e
Unable to locate 'entityTypeName' of: Product
You can set the Resource for the given entity type which would hit the resource instead -
manager.metadataStore.setEntityTypeForResourceName('GetProducts', 'Products');
But as a note it seems like a design flaw to name your entity Products instead of Product.
As far as I understand the ApiController is for performing CRUD on resources.. But I have a case where I am just calling some Helper method (Restoring a DB on a SQL server) and so I am not sure if ApiController makes sense ?
Should I only use ApiController when I am performing CRUD on something ? Or should I use ApiController for anything that does not return a view ? Is 'post' the correct HTTP verb to use ? Am I going about this all wrong ?
Id like to get it clear in my head when to use one over the other.
[HttpPost]
public JsonResult RestoreBaselineDB()
{
//Get values from web.config
string sqlServer = ConfigurationManager.AppSettings["DBTools_sqlServer"];
string backupFilePath = ConfigurationManager.AppSettings["DBTools_backupFilePath"];
string destinationDatabaseName = ConfigurationManager.AppSettings["DBTools_destinationDatabaseName"];
DatabaseHelper.RestoreDatabase(sqlServer,
backupFilePath,
destinationDatabaseName,
"c:\\temp",
"ProcessManager",
"ProcessManager_log");
return Json(new
{
Status = "OK",
}, JsonRequestBehavior.AllowGet);
}
Controller is the base class for MVC, and ApiController for web api, which can be intermixed but should have clear, distinct purposes. I would use ApiController if you intend to create a restful web service, and Controller for your web application's user interface. I wouldn't necessarily intermix the two, based on the function you are creating.
For instance, if you are creating a REST service for an API your are exposing to the world or your application, keep everything contained in a web api set of APIControllers. But consider using a Controller for returning JSON to a view in a utility scenario.
This is, of course, subjective and likely to have differing opinions.
As #Brian Mains recommends, in your situation, you should use an ApiController because, as you say, it does not return a view. Controller should be used for your UI.
The answer to your question about is ApiController just for CRUD takes you dangerously close to the REST flame wars.
A pure REST approach to this would be to think of your restore database operation as creating a DatabaseRestoreRequest resource (and therefore should be a POST).
POST <Host>/Api/DatabaseRestoreRequest
Since the restore is probably a lengthy operation (especially for large databases), the body of the POST response would represent a resource with a unique identifier and a status that could be one of
InProgress
Failed
Complete
Having done a POST to initiate the restore (status would be InProgress), you would then make a GET request, providing the unique identifier. The GET response would give the updated status. You could call GET repeatedly until the response had a status of Complete.
GET <Host>/Api/DatabaseRestoreRequest/<requestID>
You may also have a DELETE operation, which could cancel the restore operation.
DELETE <Host>/Api/DatabaseRestoreRequest/<requestID>
If this seems over complicated and unnatural to you, you could just use a pattern like that used by the Windows Azure management API (and others). This uses a URI scheme that indicates a resource in the main URI and then the operation as a query string parameter
For example, to re-image a virtual machine you would do a POST to
https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deploymentslots/<deployment-slot>/roleinstances/<role-instance-name>?comp=reimage
In your case it could be something like
POST <Host>/Api/Database?comp=restore
POST is traditionally used for this kind of operation because they are often non-idempotent. Idempotent means that if you repeat it several times it has the same effect as if you do it just once). PUT is supposed to be idempotent. POST does not have to be. This comes from the W3C:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
REST purists might decide to flame and downvote me for suggesting the second option. But hey...
I am trying to develop a RESTful Web service as an ASP.NET MVC 3 Web Application.
(I know, I should use the right tool for the job, which in this case means I should use WCF. But WCF has too many abstraction layers and is thus too big to fit inside my head. It would be cool for a research project, but I am trying to do my job. Besides I previously tried it, and now I am of the opinion that, despite its big promises, WCF sucks big time.)
Anyway, what I want to do is simple: I want my Web service to return its results as either XML or JSON, depending on the type specified in the HTTP request (by, default, JSON). How do I do that?
A Json action result already exists. MvcContrib has an XML action result you can return, or you could just use Content (xmlContent, "text/xml") as your action result.
You can query the accept header to determine which action result you would like to return. As long as your action method returns type ActionResult, it doesn't matter which type it returns.
That said, once you prove the overall concept, there are better ways to structure what you're trying to do.
A quick solution is to create an optional parameter on your Controller method, and return the view as the appropriate format.
public ActionResult GetFormattedResults(string format)
{
var data = GetResults();
ActionResult result = new JsonResult(data);
switch(format.ToLower())
{
case "xml":
result = new XmlResult(data); // this class doesn't exist in MVC3 you will need to roll your own
case "html":
result = new View(data);
}
return result;
}
You could also wrap the formatting functionality into an ActionFilter so you can reuse the functionality across controller methods.
I'm new to MVC and I've been looking through a bunch of examples.
For the HttpPost on some edits they call UpdateModel(entity).
In other examples such as:
http://www.asp.net/mvc/tutorials/mvc-music-store-part-5
UpdateModel(entity) isn't called at all.
What's the point of calling this function when it appear unneccessary in MVCMusicStore?
Apparently it " Updates the specified model instance using values from the controller's current value provider."
However I've found from the MVCMusicStore example the updated values are already posted through?
Could someone please explain this to me?
There should be no reason for you to use UpdateModel in the newer version of ASP.NET MVC
Originally it was provided because when you posted your data back to the action on your controller, a FormsCollection would be passed in to to the action and then a call to UpdateModel(entity) would be required.
However in newer versions of ASP.NET MVC the concept of ModelBinding has been introduced which will allow your actions to define a .net object to be passed in to your action methods and the model binder will take care of "binding" the values to the model.
To be completely honest, I'm not sure why they don't just deprecate the UpdateModel() method because AFAIK it's completely redundant.
Use UpdateModel for PATCH semantics. From RFC5789:
The PATCH method requests that a set of changes described in the
request entity be applied to the resource identified by the
Request-URI.
This means you are making modifications to an existing resource (e.g. from the database).
Use the object as action method parameter for PUT semantics.
The difference between the PUT and PATCH requests is reflected in the
way the server processes the enclosed entity to modify the resource
identified by the Request-URI. In a PUT request, the enclosed entity
is considered to be a modified version of the resource stored on the
origin server, and the client is requesting that the stored version be
replaced.
In practice, there's not much difference if the request contains values for all of the resource members. But if the request only contains values for a subset of the resource members, in PATCH the other members are left unmodified, and in PUT are set to their default value (usually NULL).
i don't think ModelBinding is only introduced in newest version of asp.net mvc (newest version is 3). it was present at least in v-2 so far as i can tell. when you call the updatemodel you call Modelbinding explicitly. when you receive at as action method parameter Modelbinder is called implicitly.
In Edit scenario updateModel is used when we fetch original entity from db and tell controller to update it using UpdateModel like
public ActionResult Edit(int id)
{
var entity = db.GetEntity(id);
UpdateModel(entity);
db.SaveChanges();
}
Other scenario is when you are not fetching db entity but ModelBinder gives you an entity created from form fields etc. and you tell you db that object is already there and it has been modified outside the db and you better sync with it like in MusicStore tutorial.