I am using the following in my Global.asax to change the formatting to camelCase on the client.
// Change Json data to camelCasing
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
In addition, we are using Unity, and I have a Separate Service and a custom EFContextProvider class that resturns metadata, consumed in the Controller. I assume that because I'm generating Metadata outside of the BreezeController, it then is returning the metadata in PascalCase, which my Code first DbContext is all using.
End result is that I get PascalCased Metadata(this seems incorrect from waht I expect) and camelCased entities from entityQueries but are not observable knockout properties. Any tip or ideas why my entities are not observable would be appreciated.
You don't need to use a ContractResolver for this, Breeze handles this directly via it's NamingConvention class: See the NamingConvention discussion on this page. Breeze Docs - NamingConvention.
Basically, all you need to do is call:
breeze.NamingConvention.camelCase.setAsDefault(); // a convention can self-register as the default
You can achieve this server side using the BreezeConfig.Instance.GetJsonSerializerSettings().ContractResolver.
public static void RegisterBreezePreStart() {
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "BreezeApi",
routeTemplate: "breeze/{controller}/{action}"
);
BreezeConfig.Instance.GetJsonSerializerSettings().ContractResolver
= new CamelCasePropertyNamesContractResolver();
}
Related
Hi I created a method on my Web API Controller that successfully returns the metadata as string. I am just wondering if there is a clever way of generating entities at runtime instead of generating entities in TS client side beforehand?
[HttpGet]
public string Metadata()
{
return this.dataContext.Metadata();
}
The point of generating the TypeScript entities beforehand is so that you have types and intellisense to help you write your code correctly.
But of course the EntityManager can create entities on the fly from the metadata; you just need to know the name of the EntityType:
let cust = manager.createEntity("Customer");
And you can query entities from the server without pre-generated classes:
const query = new EntityQuery('Customers').where('lastName', 'startsWith', 'C');
manager.executeQuery(query).then(qr => {
let customers = qr.results;
// do something with customers...
});
In the early days of Breeze, we always loaded the metadata from the server on-the-fly, usually as the app was starting up.
These days, I code in TypeScript, and I find it very helpful to have the metadata and classes pre-generated.
Figured it out. The above method is needed or at least one called Metadata of type HTTP GET. the data service in breeze-client needs to have the property hasServerMetadata to false and the magic happens.
I have a web API exposing ODATA from a SQL stored proc. I want to use a url like /odata/firmhierarchy(225) to pass 225 into a param for the stored proc. It just tells me that it can't find a matching resource. It hits the controller, just skips the method. Thoughts?
In webapiconfig
private static IEdmModel GenerateEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Employee>("Employees");
builder.EntitySet<Employee>("FirmHierarchy");
return builder.GetEdmModel();
}
Context:
public virtual ObjectResult<Employee> sp_EmployeeHierarchy(Nullable<int> managerEmpID)
{
var managerEmpIDParameter = managerEmpID.HasValue ?
new SqlParameter("ManagerEmpID", managerEmpID) :
new SqlParameter("ManagerEmpID", 0);
return ((IObjectContextAdapter)this).ObjectContext.ExecuteStoreQuery<Employee>("sp_EmployeeHierarchy #ManagerEmpID", managerEmpIDParameter);
}
Only method in controller:
[Queryable]
public IQueryable<Employee> GetFirmHierarchy()
{
return db.sp_EmployeeHierarchy(225).AsQueryable();
//return SingleResult.Create(db.Employees.Where(employee => employee.EmpId == key));
}
This should work:
1.Write another method in your controller:
[EnableQuery]
public IQueryable<Employee> Get([FromODataUri] int key)
{
return db.sp_EmployeeHierarchy(key).AsQueryable();
}
Please note that [EnableQuery] is an attribute introduced in Web API for OData V4. If you are still using Web API for OData V1-3, use [Queryable] still.
2.Then you can send the request
GET /odata/firmhierarchy(225)
and get the employees.
I was able to make ODATA work for a table, when auto-generated from entity framework. However, that generation process didn't want to work for a complex type returned by a Table Valued Function (similar scenario to a SP), because it didn't seem to understand where the key was.
What I found was that I could however make it work. First, I check out this article. He sets things up a bit more manually, where his Get on a companyProcessingController ends up routing for id 3 as "http://localhost:10020/odata/companyProcessing(3)" .
This surprised me. My other generated classes set up the pattern that SomeEntity became SomeEntityController, with methods like GetSomeEntities, and a routing that seemed to me to match the method but dropping the word get. Therefore, dropping the entity name from the Get method name seemed different, but it worked. Proving that the path is actually matching the controller name, not the method name.
In this Case you configure the routing using the data type you're querying for, and the beginning of the controller name. Then the actual path utilizes the beginning of the controller name as well.
And then all of this just brings us essentially to the other posted solution, assuming your controller name is firmhierarchyController
So, now, making sense of this... Try going to http://localhost:55063/odata/$metadata , where your port may differ. You'll notice that ODATA exposes a DataType, which is accessed via a DataSet. When a client tries to query into ODATA, they are trying to query against the DataSet, getting items of the DataType.
The DataSet matching the controller name (less Controller), and the Get methods can indeed just be Get without further extension of the name - and otherwise in this scenario was giving me problems.
I'm using JSON.NET and had some troubles in the past during WEBAPI objects deserialization. After doing some research I've found that the class was marked with [Serializable]. When I removed this the deserialization was just fine.
More detailed information about this can be found here:
Why won't Web API deserialize this but JSON.Net will?
Now it comes to the problem that I use binaryformatter to create a hash value calculated from this object class.
But Binaryformatter requires that the class must be marked as [Serializable].
Could you recommend me any approach to make both things work at the same time?
Found the solution:
First, check that your Newtonsoft.JSON version is greater than 4.5 or just update with NuGET
According to the version notes, both can work together starting from this version using some extra annotations.
http://james.newtonking.com/archive/2012/04/11/json-net-4-5-release-2-serializable-support-and-bug-fixes
"Now if you are serializing types that have the attribute and don’t want the new behaviour, it can either be overridden on a type using the JsonObjectAttribute"
[JsonObject]
[Serializable]
public class Foobar {
Now it is possible to use JSON.NET and, in my case, the binaryformatter with the [Serializable] attribute.
An alternative to specifying JsonObject on each class is to tell web.api to ignore Serialize attributes globally. This can be done by resetting the DefaultContractResolver on the web api JsonFormatter:
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver();
(using NewtonSoft.Json.Serialization where config is the System.Web.Http.HttpConfiguration)
As of NewtonSoft v4.5 the IgnoreSerializableAttribute property on the DefaultContractResolver is set to true but the web api wrapper, around DefaultContractResolver, has this set to false by default.
I was using a POCO with Serializable attribute. In the first case while Posting Request to a WebApi worked by using the following method:
JsonMediaTypeFormatter f = new JsonMediaTypeFormatter()
{
SerializerSettings = new JsonSerializerSettings()
{
ContractResolver = new DefaultContractResolver()
{
IgnoreSerializableAttribute = true
}
}
};
var result = client.PostAsJsonAsync<IEnumerable<Company>>("company/savecompanies", companies).Result;
//I have truncated the below class for demo purpose
[Serializable]
public class Company
{
public string CompanyName {get;set;}
}
However, when I tried to read the response from WebApi (Which was posted back as JSON), the object was not properly deserialized. There was not error, but property values were null. The below code did not work:
var readObject = result.Content.ReadAsAsync<IEnumerable<Company>>().Result;
I read the documentation as given on Newtonsoft.Json website https://www.newtonsoft.com/json/help/html/SerializationAttributes.htm and found the following and I quote from that site:
Json.NET attributes take precedence over standard .NET serialization
attributes (e.g. if both JsonPropertyAttribute and DataMemberAttribute
are present on a property and both customize the name, the name from
JsonPropertyAttribute will be used).
So, it was clear if Newtonsoft.Json attributes are present before the standard .NET attributes they will take precedence. Hence I could use the same class for two purposes. One, when I want to post to a WebApi, Newtonsoft Json serializer will kick in and Two, when I want to use BinaryFormatter.Serialize() method std .NET Serializable attribute will work.
The same was confirmed with the answer given above by #Javier.
So I modified the Company Class as under:
[JsonObject]
[Serializable]
public class Company
{
public string CompanyName {get;set;}
}
I was able to use the same class for both purposes. And there was no need for the below code:
JsonMediaTypeFormatter f = new JsonMediaTypeFormatter()
{
SerializerSettings = new JsonSerializerSettings()
{
ContractResolver = new DefaultContractResolver()
{
IgnoreSerializableAttribute = true
}
}
};
I'm trying to return a JSON list of stuff from my server via an ASP.NET MVC front layer:
var stuff = repo.GetStuff();
return Json(stuff);
However, instead of the expected JSON, I get an error message stating
A circular reference was detected while serializing an object of type 'System.Reflection.RuntimeModule'.
I think I've found where this happens, but to explain it I need a simple example domain model as follows:
I am (lazily?) loading a selection of documents from NHibernate, like so:
var session = getNHibernateSession();
var query = new NhQueryable<Document>(session.GetSessionImplementation());
var docs = query.ToList().AsEnumerable();
I then pass the documents to return a JsonResult in my controller:
return Json(docs, JsonRequestBehavior.AllowGet);
Now, when Json() serailizes the collection, it walks over the properties of a document, finds a person. It serializes that person, and finds a project. It serializes the project, and finds - that's right - the person again! Since I'm lazy loading, it can just keep walking for ever if nothing stops it, but it's stopped by a circular reference error.
I don't really need to go all these levels down (I'd be fine without loading the project in the first place) - can I somehow affect how Json() serializes this collection, to not go further than, say, 2 levels down? I've googled around a little, but most of what I find seems to be from people who decided to use a serializing library directly, rather than just using the built-in functionality in .NET MVC. (Note: The solution to this problem must be possible to apply specifically to this case, since I might want to get JSON lists of people, including projects, somewhere else in the application...)
If you are retrieving Json, you have a service api. You have to design the api besides the implementation. Does the page that will be using it need all those fields and collections? probably not. What about adding more properties for other features and services? They will start appear in all the requests.
What you need is to use a ViewModel or just an anonymous type with the desired structure:
var session = getNHibernateSession();
var query = new NhQueryable<Document>(session.GetSessionImplementation());
var docs = query.ToList();
var result = query.Select(x => new {
x.Id,
x.Name,
People = new { p.Id,
p.Name,
p.Title
}
});
return Json( result, JsonRequestBehavior.AllowGet);
This way you can control what is being rendered and how.
It's already been answered here.
Also, it's generally a bad idea to expose your domain entities like this. If it's for read-only purposes it might not be so bad, but if any of your action methods accept a domain entity, then a specifically formatted request can overwrite properties on your domain entity that you don't want to (such as your PK).
To preserve object references in JSON, add the following code to Application_Start method in the Global.asax file:
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All;
I know Grails has a map based constructor for domain objects, to which you can pass the params of a URL to and it will apply the appropriate field settings to the object using introspection, like this...
myDomainInstance = new MyObject(params)
I was wondering whether there was an equivalent method of taking the params and applying them to an existing object and updating values in the same way that the map constructor must work, something like...
myDomainInstance = params
or
myDomainInstance = fromParams(params)
Am I just wishful thinking or does such a thing exist? I can code it up myself but would rather not if it exists already.
Thanks
Adapted from the grails user guide:
obj = MyObject.get(1)
obj.properties = params
Check out the documentation for 'params' under the controller section for more information.
It really depends on what you are trying to do but an equivalent approach use databinding.
def sc = new SaveCommand()
bindData(sc, params)
This give you the benefit of using custom binding. If let say your date format is not the default one you can redefine it through a bean like this:
public class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("dd/MM/yyyy"), true));
}
}