How to Optionally exclude a class member when serializing to XML - c#

I just took over a fairly large project. One of my tasks is to modify the code that gets rate quotes from FedEx. Currently, in order to get a set of rate quotes for a shipment that includes quotes for each "ServiceType" (Ground, 2-day, overnight, etc.) the code makes one call for each type. FedEx offers a web service that is used to get this information. After doing a little research, it looks like this web service can return multiple ServiceType quotes with a single round-trip. To do this, I'm supposed to "leave the service type out of the request." (Here's the question that pointed me in that direction.)
So I know that I can exclude the service type property from the serialization by decorating the property with, [System.Xml.Serialization.XmlIgnoreAttribute()]. But how can I do that only when I want results for all the ServiceType values and still be able to pass a single service type for the cases where I know what shipping method the user wants?
EDIT: FedEx's documentation indicates that this field is optional. Some basic testing shows that excluding it from the request with the XmlIgnoreAttribute does return data for multiple ServiceTypes.

If you implement a public bool ShouldSerializeXXX() function alongside the XXX property being serialized, XmlSerializer will ignore the corresponding XXX property when the function returns false. You'll have to have some basis for setting this (maybe the XXX property can be null? or you can grab some other state to make the decision.)
So, something along these lines:
public class MyClass
{
public ServiceType? ServiceType { get; set; }
public bool ShouldSerializeServiceType() { return ServiceType.HasValue; }
}

Related

How to assert that a API response has a specific structure?

I have a SpecFlow test definition set up where I want to assert that the response have a specific collection of fields in its response. For example I have this particular expected response from the API:
{
isActive: false,
lastProcessed: "2020-11-03T19:03:16.537"
}
What I want to verify is that the response contains those two fields, not necessarily the value those fields contain. I tried the following method:
Assert.NotNull(response.Model.isActive);
Assert.NotNull(response.Model.lastProcessed);
But I'm getting an error using this method:
Do not use Assert.NotNull() on value type 'bool'
How else can I make sure the response structure is as expected other than using "NotNull()"?
The Solution:
Following the accepted answer, I serialized the model returned from the API call into JSON and parsed it into a JObject. Then I used the ContainsKey() method to assert it.
JObject jObject = JObject.Parse(JsonConvert.SerializeObject(response.Model));
Assert.True(jObject.ContainsKey("isActive"));
I don't know what packages you use for sending requests and deserialization but if you could get the response content as a raw json string you could then use Newtonsoft.JSON to parse the response into a JObject with JObject.Parse(responseContent). JObject has a method called ContainsKey(propertyName) which determines whether there is a field of a specified name in the object. You could assert if it returns true for the desired property names.
Edit
Regarding Greg's answer below. The original error is in fact caused by bool not being a nullable type and making it nullable in the model would fix the error. However, this solution is not ideal. In some cases null can be a valid value returned by the API and this would generate false negatives. e.g. if we recieved:
{
isActive: null,
lastProcessed: "2020-11-03T19:03:16.537"
}
then Assert.NotNull(response.Model.isActive) would yield a negative test result even though the field is present in the json, and that's what we wanted to check.
So theoretically if we are 100% sure that null will never be returned by the API itself, then we could do it that way, but it won't be a universal method. Also not very descriptive of what we are trying to achieve ;)
Since the isActive property is a bool you'll need to assert that it is false. If instead you want a true or false value, and then something to represent that it is missing, use a nullable boolean instead in your DTO:
public class YourDTO
{
public bool? isActive { get; set; }
...
}
Then you can assert isActive is null, true or false.
Alternative: If you cannot update the original data transfer object, then this might be a good use case for writing your own code to call the web service and map the JSON response to your own DTO used just for your tests.
This could be a large amount of work, however. The advantage is your test code is truly decoupled from the code it tests. I've done this with applications that use a database as well. It is extra work, but it allows your tests to use whatever data structure makes sense for the test.

C# attributes used for information or to import extern functions?

I'm a bit confused about C#'s use of attributes. At first I thought it was simply used to give program code additional information through the use of the [Obsolete] attribute. Now I find that [Dllimport] can be used to import a dynamic linked library and its functions. Can attributes import .exe files and other kind of files?
A last question, for programmers working in C# every day, how much do you use attributes, and do you use it for anything else than extending information and importing dll's?
Simply said, attributes are just metadata attached to classes or methods, at the very base.
The compiler, however, reads through your code, and runs specific actions for specific attributes it encounters while doing so, hardcoded into it. E.g., when it finds a DllImportAttribute on a method, it will resolve it to an external symbol (again, this is a very simplified explanation).
When it finds an ObsoleteAttribute, it emits a warning of deprecation.
Your own attributes (which you can create with a class inheriting from the Attribute base class) will not have an effect on the default compiler. But you (or other libraries) can also scan for them at runtime, opening up many possibilities and leading to your second question:
I typically use them to do meta programming. For example, imagine a custom network server handling packets of a specific format, implemented in different classes. Each packet format is recognized by reading an integer value. Now I need to find the correct class to instantiate for that integer.
I could do that with a switch..case or dictionary mapping integer -> packet which I extend every time I add a packet, but that is ugly since I have to touch code possibly far away from the actual Packet class whenever I add or delete a packet. I may not even know about the switch or dictionary in case the server is implemented in another assembly than my packets (modularity / extensibility)!
Instead, I create a custom PacketAttribute, storing an integer property set via the attribute, and decorate all my Packet classes with it. The server only has to scan through my assembly types at startup (via reflection) and build a dictionary of integer -> packet pairs automatically. Of course I could scan my assembly every time I need a packet, but that's probably a bit slow performance-wise.
There are APIs which are much more attribute heavy, like controllers in ASP.NET Core: You map full request URLs to methods in handler classes with them, which then execute the server code. Even URL parameters are mapped to parameters in that way.
Debuggers can also make use of attributes. For example, decorating a class with the DebuggerDisplayAttribute lets you provide a custom string displayed for the instances of the class when inspecting them in Visual Studio, which has a specific format and can directly show the values of important members.
You can see, attributes can be very powerful if utilized nicely. The comments give some more references! :)
To answer the second part of your questions, they are also used, for example, in setting validation and display attributes for both client and server side use in a web application. For example:
[Display(Name = "Person's age")]
[Required(ErrorMessage = "Persons's age is required")]
[RangeCheck(13, 59, ErrorMessage = "The age must be between 13 and 59")]
public int? PersonsAgeAtBooking { get; set; }
Or to decorate enums for use in display
public enum YesNoOnlyEnum
{
[Description("Yes")]
Yes = 1,
[Description("No")]
No = 2
}
There are many other uses.

web url validator to class level validation

I have a simple class and corresponding properties. I would like to add some validation rules (to a web property). I want to check that the web address is valid. What are the types of conditions I would need to check for?
My thinking:
I have to require this format www.example.sometext
Should I check for valid .sometext endings (i.e. .com, .org, etc.) Problem is there are basically unlimited of these now.
So my question who would I add a validation rule on the class level to handle this?
public string WebAddress { get; set; }
You can use Uri.IsWellFormedUriString method. It will return true if the string was well-formed, if not it will return false.
Link to MSDN: IsWellFormedUriString

Get operation name in Message Inspector?

Im using the IClientMessageInspector to log in/out messages but the problem is that I canĀ“t find how to get the operation name from AfterReceivedReply and BeforeSendRequest.
I have tested the following :
if ((action = reply.Headers.Action.Split('/').LastOrDefault()) != null)
{
callInformation.Action = action;
callInformation.Address = reply.Headers.Action.Replace(action, "");
}
This works fine in BeforeSendRequest but in the AfterReveivedReply it returns something different, often with the "Response" on the end?
How do I only get the operation name in those methods?
Say, that my operation is named MyOperation and a OperationContract attribute states the action = "MyOpeation" (wrong spelling). This result of this is that MyOpeation will be extracted in BeforeSendRequest while the AfterReceiveReply will return MyOperationResponse.
So the BeforeSendRequest will extract the stated action in the attribute and the AfterReceiveReply will extract the real operation name but with the add of "Response" on the end?
Its important to be able to match the in/out messages and the only way of doing this as I see it is to match the operation names but if that is not possible then I do not see a good solution to this?
I have seen solution when using OperationContext.Current.IncomingMessageHeaders.Action but the OperationContect.Current is null when doing this on the client side.
From your question I assume you want to match In/Out messages by any means - the framework provides for this:
In the implementation of IClientMessageInspector.BeforeSendRequest you can return a unique correlationState which in turn allows you to relate the reply message in your implementation of IClientMessageInspector.AfterReceiveReply since the Framework will call your implementation with it as the second parameter.
EDIT - as per comments below:
IF you really need to get the name of the operation/method called you could do this is by implementing IClientMessageFormatter.SerializeRequest OR IParameterInspector - this will allow you to to record which method with which parameters have been called and what Message object the framework created for it.

How do I serialize a dynamic object?

I want to make a Configuration Data Manager. This would allow multiple services to store and access configuration data that is common to all of them.
For the purposes of the Manager, I've decided to create a configuration class object - basically what every configuration data entry would look like:
Name, type, and value.
In the object these would all be strings that discribe the configuration data object itself. Once it has gotten this data from its database as strings, it would put it into this configuration object.
Then, I want it to send it through WCF to its destination. BUT, I don't want to send a serialized version of the configuration object, but rather a serialized version of the object discribed by the configuration object.
The reason I'd like to do this is so that
The Data Manager does not need to know anything about the configuration data.
So I can add configuration objects easily without changing the service. Of course, I should be able to do all of the CRUD operations, not just read.
Summary:
Input: string of name, type and value
Output: Serialized output of the object; the object itself is "type name = value"
Questions:
Is this a good method for storing and accessing the data?
How can I/can I serialize in this manner?
What would the function prototype of a getConfigurationData method look like?
I have decided to go in a different direction, thanks for the help.
Is this a good method for storing and accessing the data?
That is difficult to answer, the best I can give you is both a "yes" and a "No". Yes, It's not a bad idea to isolate the serialization/rehydration of this data.... and No, I don't really care much for the way you describe doing it. I'm not sure I would want it stored in text unless I plan on editing it by hand, and if I'm editing it by hand, I'm not sure I'd want it in a database. It could be done; just not sure you're really on the right track yet.
How can I/can I serialize in this manner?
Don't build your own, never that. Use a well-known format that already exists. Either XML or JSON will serve for hand-editable, or there are several binary formats (BSON, protobuffers) if you do not need to be able to edit it.
What would the function prototype of a getConfigurationData method look like?
I would first break-down the 'general' aka common configuration into a seperate call from the service specific configuration. This enables getConfigurationData to simply return a rich type for common information. Then either add a extra param and property for service specific data, or add another method. As an example:
[DataContract]
public class ConfigurationInfo
{
[DataMember]
public string Foo;
...
// This string is a json/xml blob specific to the 'svcType' parameter
[DataMember]
public string ServiceConfig;
}
[DataContract]
public interface IServiceHost
{
ConfigurationInfo GetConfigurationData(string svcType);
}
Obviously you place a little burden on the caller to parse the 'ServiceConfig'; however, your server can treat it as an opaque string value. It's only job is to associate it with the appropriate svcType and store/fetch the correct value.

Categories

Resources