I created a Web API using VS 2012. I have a method with a custom object parameter that I am passing JSON to via Fiddler for testing:
[HttpPost, HttpPut]
public HttpResponseMessage UpsertProject(Projects p)
{
...
}
My Projects object has about a dozen properties marked as JsonIgnore. My assumption was that when my object was serialized into Json those properties would be ignored...which is true. However, when I debug my method I'm noticing that all the object properties marked with JsonIgnore are set to null even if the Json that I pass in from Fiddler is setting them. I also try to get data as Json and deserialize it into a new instance of the object but that also does not set the properties that are marked JsonIngore. I knew JsonIgnore would work for serializing but didn't think it would prevent properties from being set when deserializing. What's frustrating is I know that ScriptIgnore doesn't behave this way, but I want to use JSON.net to handle my serializing/deserializing. I've also created a windows app and tested the same serializing/deserializing functionality and it works in it. So I'm wondering if this is a Web API limitation with the JsonIgnore attribute?
If it works the way you want in the Windows application but not in the Web API, that tells me that the JSON serializer settings are different between the two. What settings are you using in the Windows app that makes it work? You can take those settings and apply them to the Web API serializer in the Register method of the WebApiConfig class (in the App_Start folder of your Web API project). For example:
JsonSerializerSettings jsonSettings = config.Formatters.JsonFormatter.SerializerSettings;
jsonSettings.NullValueHandling = NullValueHandling.Ignore;
jsonSettings.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate;
...
EDIT
OK, so if I understand you correctly, based on your most recent comments, you want everything to be deserialized if possible, but you only want two specific properties to be serialized and those apparently do not have null or default values. In that case, there are two approaches you can take:
Set the properties that you don't want serialized to null or zero or false (the default value) just before serializing. Because you have DefaultValueHandling set to Ignore, this will cause those properties not to be serialized.
Create several boolean ShouldSerializeXXX() methods in your class where XXX is the name of each property you don't want serialized. These methods should return false. See the first answer of this question for an example.
Don't use JsonIgnore because, as you have seen, this will cause the property to be completely ignored by Json.Net, both for serializing and deserializing.
Related
I'm currently building a Web API in net-core that has the following requirements:
All web transactions must have a unique Guid identifier for each endpoint
If an endpoint is hit with a previously used Guid, then the response that was given for this Guid is returned again
I was attempting to implement this by JsonSerializing the IActionResult inside the WebApi controller, but I ran into an issue where I can't deserialize all IActionResult responses since some don't have a constructor.
For example:
JsonSerializationException: Unable to find a constructor to use for type Microsoft.AspNetCore.Mvc.CreatedResult. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.
Does anybody know if it's possible to work around this?
Personally, I'd use the response caching middleware. You can make it vary on your GUID, so as long as that is included in the request, it will only render the action if the GUID is different.
Short of that, if you want to handle this manually, cache the JSON you're intending to return, not the full response object. Then, you do not need to re-query the database, etc., and you simply return the response, which is not all that much overhead.
Just starting to investigate the Yodlee soap example and I am having problems with an
Unable to cast object of type 'System.Xml.XmlNode[]' to type 'BankData'.
error in the DisplayBankData class. I have tried downloading and creating the Yodlee dll from the wdsl definitions from 2014Q3WSDLs as well as using the DLL that came with the download with no success. The same problem is also happening with the CardData class (and possibly others)
Am I missing something or is there a problem with the wsdl definitions supplied?
After spending many hours trying to work out whats going on here, I have finally worked out that there is something wrong with either the WDSL files generated by Yodlee, or the way that WSDL.exe interprets the WSDL files.
The actual cause of it is because the WSDL does not seem to indicate what type is returned under ItemData1.Accounts, this is because it can be either BankData or CardData, since VisualStudio does not know what type to expect, it de-serialises the object as an XML node.
The way I have managed to get round this is when you use the WSDL.exe to produce the yodleeProxies.vb file, you will need to go into the generated file and then find the defenition for the ItemData1 Class
Partial Public Class ItemData1
You will need to change
Public Property accounts As Object()
to
Public Property accounts As BankData()
Then it knows that the object will be of type BankData
I have also added a new property that expects CardData so that CardData will appear under this one, and will de-serialise correctly
Public Property accounts2 As CardData()
Get
Return Me.accountsField
End Get
Set(value As CardData())
Me.accountsField = value
End Set
End Property
So thats my hack on how to resolve it, if any one else has worked out a more elegant way of getting round this, please do let me know.
I found adding the XmlInclude() attribute below to the ItemData1 class in the proxy file glyn johnston mentioned solves the issue - apparently the deserializer doesn't know to consider ItemAccountData and its descendants when deserializing that property.
I believe 'accounts' should be kept as an array of objects as there are several types that inherit from ItemAccountData including CardData, BankData and others, and upon inspecting the WSDL directly 'accounts' appears to be defined as a 'List' of type 'anyType'.
It is possible it is defined this way to allow for adding newer types in the future without causing de-serialization issues, so basically you need to inspect each element in the array and determine its type individually, ignoring the types you do not know or care about.
...
[System.Xml.Serialization.XmlInclude(typeof(ItemAccountData))]
public partial class ItemData1 {
...
I believe the source of the problem is the Xml deserializer doesn't consider types that aren't somehow tied to the definition of the class ItemData1 via its method signatures, properties etc. and the XmlInclude() is the attribute to use to fix that.
OK, I want to make sure I cover my situation and everything I've tried thoroughly. I'm pretty sure what I need/want can be done, but I haven't quite found the perfect combination for success.
I'm utilizing Entity Framework 4 RTM and its POCO support. I'm looking to query for an entity (Config) that contains a many-to-many relationship with another entity (App). I turn off lazy loading and disable proxy creation for the context and explicitly load the navigation property (either through .Include() or .LoadProperty()). However, when the navigation property is loaded (that is, Apps is loaded for a given Config), the App objects that were loaded already contain references to the Configs that have been brought to memory. This creates a circular reference.
Now I know the DataContractSerializer that WCF uses can handle circular references, by setting the preserveObjectReferences parameter to true. I've tried this with a couple of different attribute implementations I've found online. It is needed to prevent the "the object graph contains circular references and cannot be serialized" error. However, it doesn't prevent the serialization of the entire graph, back and forth between Config and App.
If I invoke it via WcfTestClient.exe, I get a stackoverflow (ha!) exception from the client and I'm hosed. I get different results from different invocation environments (C# unit test with a local reference to the web service appears to work ok though I still can drill back and forth between Configs and Apps endlessly, but calling it from a coldfusion environment only returns the first Config in the list and errors out on the others.) My main goal is to have a serialized representation of the graph I explicitly load from EF (ie: list of Configs, each with their Apps, but no App back to Config navigation.)
NOTE: I've also tried using the ProxyDataContractResolver technique and keeping the proxy creation enabled from my context. This blows up complaining about unknown types encountered. I read that the ProxyDataContractResolver didn't fully work in Beta2, but should work in RTM.
For some reference, here is roughly how I'm querying the data in the service:
var repo = BootStrapper.AppCtx["AppMeta.ConfigRepository"] as IRepository<Config>;
repo.DisableLazyLoading();
repo.DisableProxyCreation();
//var temp2 = repo.Include(cfg => cfg.Apps).Where(cfg => cfg.Environment.Equals(environment)).ToArray();
var temp2 = repo.FindAll(cfg => cfg.Environment.Equals(environment)).ToArray();
foreach (var cfg in temp2)
{
repo.LoadProperty(cfg, c => c.Apps);
}
return temp2;
I think the crux of my problem is when loading up navigation properties for POCO objects from Entity Framework 4, it prepopulates navigation properties for objects already in memory. This in turn hoses up the WCF serialization, despite every effort made to properly handle circular references.
I know it's a lot of information, but it's really standing in my way of going forward with EF4/POCO in our system. I've found several articles and blogs touching upon these subjects, but for the life of me, I cannot resolve this issue. Feel free to simply ask questions and help me brainstorm this situation.
PS: For the sake of being thorough, I am injecting the WCF services using the HEAD build of Spring.NET for the fix to Spring.ServiceModel.Activation.ServiceHostFactory. However I don't think this is the source of the problem.
EDIT: The ProxyDataContractResolver class works correctly if I don't have the circular references. (i.e.: I make the setter of App.Configs to be private, which prevents serialization of the property.) It blows up, it appears, when it hits Configs via the App object -- they don't seem to be recognized as the same type as the top level Configs.
EDIT2: It appears that either EF or WCF doesn't recognize that the entities are indeed equal. i.e.: 'Config' is the same as a particular 'Config.Apps[x].Configs[y]'. The entity keys are properly set in the CSDL for each model and I've overridden the Equals() function to compare entities based on their 'Id' property. This fits the symptoms as no circular reference error is thrown, yet it is indeed a circular reference (and blows up WcfTestClient.exe) AND the ProxyDataContractResolver blows up when it hits the 'Config.Apps[x].Configs[y]' level of Configs. (It doesn't know how to map a Config proxy. The ProxyDataContractResolver works otherwise. It's like it knows how to handle the initial round of entities, but the second level it considers as different entities.)
Wow, I can be wordy. Sorry folks!
You might want to check out my blog post on this specific scenario - please email me if it doesn't help fix your current predicament! I've included a sample solution as well.
Please drop me some feedback either way, I'd really like to hear from more people on this particular issue - especially with the implementation problems on the client end of things.
hrmm, I may not have fully understood the issue, but everytime I run into circular references with WCF the answer is to change [DataContract] on the offending classes to [DataContract(IsReference = true)].
This is a huge help compared to all the drek of messing with the contract resolvers that was needed pre WCF 3.5 SP1.
Hope this helps.
Faced the same issue today and used Value Injecter to solve it. It's as simple as:
var dynamicProxyMember = _repository.FindOne<Member>(m=>m.Id = 1);
var member = new Member().InjectFrom(dynamicProxyMember) as Member;
We couldnt afford disabling ProxyCreation
Try setting myContext.ContextOptions.ProxyCreationEnabled = false;
If the problem is solved (like mine) then you've not followed the steps mentioned in: http://msdn.microsoft.com/en-us/library/ee705457.aspx
This solved the problem for me.
You can use the ApplyDataContractResolverAttribute and a ProxyDataContractResolver along with the CyclicReferencesAwareAttribute. At first this produces error like this one - as if there is no DataContractResolver specified at all:
Type 'System.Data.Entity.DynamicProxies.Whatever_E6......A9' with data contract name 'Whatever_E6......A9:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
It will work with one simple change.
In the ApplyCyclicDataContractSerializerOperationBehavior, the constructors for the DataContractSerializer must also pass in the DataContractResolver. This is left out of all the versions I have seen online.
Example:
public class ApplyCyclicDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
private readonly Int32 _maxItemsInObjectGraph;
private readonly bool _ignoreExtensionDataObject;
public ApplyCyclicDataContractSerializerOperationBehavior(OperationDescription operationDescription, Int32 maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool preserveObjectReferences)
: base(operationDescription)
{
_maxItemsInObjectGraph = maxItemsInObjectGraph;
_ignoreExtensionDataObject = ignoreExtensionDataObject;
}
public override XmlObjectSerializer CreateSerializer(Type type, String name, String ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes,
_maxItemsInObjectGraph,
_ignoreExtensionDataObject,
true,
null /*dataContractSurrogate*/,
DataContractResolver); // <-----------------------------
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes,
_maxItemsInObjectGraph,
_ignoreExtensionDataObject,
true,
null /*dataContractSurrogate*/,
DataContractResolver); // <-----------------------------
}
}
If I have an object that holds the parameters for my method. I need to change the Object to have an additional property. I have full control over the server, but not over all of the clients. Will this change make those clients break?
I am using a self-hosted service with a binary endpoint.
I am new to WCF so my apologies if this is a silly question.
I guess you are asking about a class that represents your DataContract.
Learn about DataContract versioning and how various changes in your DataContract affect the compatibility in MSDN
In short the answer is No, it will not break the client code. The serialized graph of the data contract will deserialize to the available data members matching by their names and assigned through the property setter method. Obviously in this case, your newly added data member will not have value. Since you have full control on the server side code, you just have to make sure this newly added member need to be dealt in such a way that it is meaningful in the new implementation and allow for default/unassigned value.
I have two .NET 3.5 WCF services build with VS2008.
I have two WCF clients in Silverlight to consume these services. The clients are generated with the 'Add Service Reference'. I am using Silverlight 4.
ONE of the proxies is generated with Specified properties for each property. This is a 'message-in' class for my service method :
// properties are generated for each of these fields
private long customerProfileIdField;
private bool customerProfileIdFieldSpecified;
private bool testEnvField;
private bool testEnvFieldSpecified;
Now my other service (still with a Silverlight client) does NOT generate Specified properties.
Now I don't care about 'tenets of good SOA'. I just want to get rid of these damn properties because in the context of what I'm doing I absolutely hate them.
There has to be some difference between the two services - but I don't want to have to completely rip them apart to find out the difference.
A similar question before had the answer 'you cant do it' - which is definitely not true because I have it - I just don't know what I did differently.
Edit: I am now in a situation where I regenerate my Silverlight 4 proxy to my 3.5 WCF service (all on the same localhost machine) that sometimes I get 'Specified' properties and sometimes I don't. I no longer think (as I suspected originally) that this is due solely to some endpoint configuration or service level [attribute]. Theres certain triggers in the message itself that cause Specified to be generated (or not). There may be many factors involved or it may be something very simple.
try this in your WCF service where the property is declared
[DataMember(IsRequired=true)]
public bool testEnvField { get; set; }
IsRequired=true will negate the need for the testEnvFieldSpecified property
These extra Specified properties are generated for value types which are being specified as optional in either the contract or the attribute markup.
As value types have a value by default, the extra Specified flags are being added for these properties, to allow the client (and server) to distinguish between something explicitly not specified or explicitly specified - which may well be set to the default value. Without it, integers would always end up being 0 (and being serialized) even if you don't set them (because of the mapping to int) in your client code. So when you do, you need to also make sure that you set the Specified flag to true, otherwise these properties will not get serialized.
So to prevent these flags being generated for value types, you would have to change the contract to make these value type properties mandatory, instead of optional.
Hope that makes sense.
OK I've found one thing so far that will cause Specified properties to be generated:
The presence of an XTypedElement in the message.
These are used by Linq2XSD. I was returning an element from a Linq2XSD model.
This triggered Specified properties to be generated EVERYTHING in all my classes :
public XTypedElement Foo { get; set; }
This however didn't :
public XElement Foo { get; set; }
Still curious as to why this is, and if there are any other things that trigger this.
NOTE: I realize this is an old question. I'm adding this here because this question comes up as a top result on Google, and it's helpful information for whoever comes looking.
Try adding this line into your operation contract declaration:
[XmlSerializerFormat]
It should look something like this:
namespace WebServiceContract
{
[ServiceContract(Namespace = "http://namespace")]
[XmlSerializerFormat] //This line here will cause it to serialize the "optional" parameters correctly, and not generate the extra
interface InterfaceName
{
/*...Your web service stuff here...*/
}
}
I found that if I put a DataTable in a service DataContract then the generated client will use xml serializer and thus generate the *IsSpecified members.