Response class with polymorphic property hides deriving classes - c#

I have a response class that looks like this:
[SwaggerResponse(HttpStatusCode.OK, "List of something returned", Type = typeof(APIResponse))]
[HttpGet]
public HttpResponseMessage QuerySomething()
{
...
}
The APIResponse class looks like this:
public class APIResponse
{
public string Something { get; set; }
public IResponseDetails ResponseDetails { get; set; }
}
As you can see, the property ResponseDetails is an interface, and I put other classes there, depending on the logic. For example:
public class SomethingDetails : IResponseDetails
{
public int Id { get; set; }
}
So, the problem is:
When I generate the swagger json file, I don't see anything about the SomethingDetails class.
Only IResponseDetails appears as a class:
public partial class IResponseDetails
{
}
How can I expose the deriving classes like SomethingDetails?

First thing install from nuget: Swashbuckle.AspNetCore.Annotations
Then,you have to enable annotations on Startup:
services.AddSwaggerGen(config =>
{
config.SwaggerDoc("v1", new OpenApiInfo
{
Title = "title",
Version = "1"
});
config.EnableAnnotations();//try adding this line
});

Related

deserialize integer into a string

Is there a way to deserialize an integer into a string ? I need it for compatibility reason.
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Abc.Test
{
[JsonSerializable(typeof(OrderInfo), GenerationMode = JsonSourceGenerationMode.Metadata)]
public partial class OrderInfoContext : JsonSerializerContext
{ }
public partial class OrderInfo
{
public string UserReference { get; set; }
}
public class Program
{
static void Main(string[] args)
{
var json = #"{""UserReference"": 123}"; // <---- how having 123 deserialize as a string?
var s = JsonSerializer.Deserialize(json, OrderInfoContext.Default.OrderInfo);
}
}
}
In some cases it can make sense to separate your serialization objects (aka DTOs) from your domain objects. This give you several benefits:
Allow your domain objects to have behavior defined, without affecting serialization.
A place to handle any complicated changes to the model without losing backwards compatibility.
Allow the serialization objects to fulfill requirements like public setters, without affecting the usage in the rest of the code.
Ex:
public class OrderInfoDTO
{
public int UserReference { get; set; }
public OrderInfo ToModel() => new OrderInfo(UserReference.ToString();
}
public class OrderInfo{
public string UserReference {get;}
public OrderInfo(string userReference) => UserReference = userReference;
}
You can use a custom converter on a property. I'll look something like:
public partial class OrderInfo
{
[JsonConverter(typeof(YourCustomConverter))]
public string UserReference { get; set; }
}

How to automatically include type information when serializing?

Is it possible to specify that I always want type-information in the json object when serializing a property in an class?
(Ideally with Newtonsoft).
I'm thinking something like this:
public abstract class Value {...}
public class BigValue : Value {...}
public class SmallValue : Value {...}
public class ValueContainer
{
[JsonSetting(TypenameHandling = TypenameHandling.All)] // <--- Something like this?
public Value TheValue { get; set; }
}
I am aware that I could specify this behavior when doing the parsing with a custom converter.
But I want to include the typeinformation every time objects of this type is serialized, without manually having to specify which serialization options to use.
Newtonsoft.Json's JsonPropertyAttribute has TypeNameHandling property which you can set:
public class Root
{
[JsonProperty(TypeNameHandling = TypeNameHandling.All)]
public Base Prop { get; set; }
}
public class Base
{
public int IntProp { get; set; }
}
public class Child:Base
{
}
// Example:
var result = JsonConvert.SerializeObject(new Root
{
Prop = new Child()
});
Console.WriteLine(result); // prints {"Prop":{"$type":"SOAnswers.TestTypeNamehandling+Child, SOAnswers","IntProp":0}}

AutoMapper - Map Derived Class To Dto

Im trying to map a Class which inherits from a base class to a dto.
public class LaunchConfiguration : Document
{
public string Brand { get; set; }
public string SettingName{ get; set; }
}
public class LaunchConfigurationDto
{
public string Brand { get; set; }
public string SettingName{ get; set; }
}
The point of the dto is to hide the fields of the base document when it gets returned to the user. This is my Map configuration
public class DtoProfile : Profile
{
public DtoProfile()
{
CreateMap<LaunchConfiguration,LaunchConfigurationDto>();
}
};
The problem im having is that auto mapper complains about the base class properties which are not mapped . "Unmapped members were found." The properties are the ones on the base class. I have tried specifying this to be ignored in the profile to no avail . Can anyone specify the correct way to do this ?
My ConfigureServices Method incase anyone is wondering :
public void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = Configuration["ApiInformation:Name"], Version = Configuration["ApiInformation:Version"] });
c.DescribeAllEnumsAsStrings();
});
services.AddAutoMapper(mc =>
{
mc.AddProfile(new DtoProfile());
});
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
options.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
});
}
My Base Class :
public class Document : IDocument, IDocument<Guid>
{
public Document()
{
this.Id = Guid.NewGuid();
this.AddedAtUtc = DateTime.UtcNow;
}
/// <summary>The Id of the document</summary>
[BsonId]
public Guid Id { get; set; }
/// <summary>The datetime in UTC at which the document was added.</summary>
public DateTime AddedAtUtc { get; set; }
/// <summary>The version of the schema of the document</summary>
public int Version { get; set; }
}
My implementation where _mapper is my Injected mapper and _repo My Injected Repo. Exception Occurs on Map Method call
Task ILaunchConfigurationService<LaunchConfigurationDto >.InsertLaunchConfiguration(LaunchConfigurationDto model)
{
var mapped = _mapper.Map<LaunchConfiguration >(model);
return _repo.AddOneAsync(mapped);
}
Your problem should be solved by simply adding ReverseMap() to CreateMap call:
public class DtoProfile : Profile
{
public DtoProfile()
{
CreateMap<LaunchConfiguration, LaunchConfigurationDto>().ReverseMap();
}
};
Automapper creates one way map by default. ReverseMap is just a sugar for creating reverse map in case there are no peculiar mappings in one way. You could also do it like this:
public class DtoProfile : Profile
{
public DtoProfile()
{
CreateMap<LaunchConfiguration, LaunchConfigurationDto>();
CreateMap<LaunchConfigurationDto, LaunchConfiguration>();
}
};
You can read more about this in documentation
However I cannot guarantee you that you will not experience exceptions from database with your current implementation on commiting changes.

C# JsonConvertDeserialization returning null values

I am trying to understand why I am getting null values for the following:
Json:
{
"IdentityService": {
"IdentityTtlInSeconds": "90",
"LookupDelayInMillis": "3000"
}
}
Class:
public class IdentityService
{
public string IdentityTtlInSeconds { get; set; }
public string LookupDelayInMillis { get; set; }
}
Called with :
_identityService = JsonConvert.DeserializeObject<IdentityService>(itemAsString);
The class is instantiated but the values for IdentityTtlInSeconds and LookupDelayInMillis are null. I cannot see why they should be
You need one more class - an object which has one property called IdentityService:
public class RootObject
{
public IdentityService IdentityService { get; set; }
}
You need this class because JSON that you have has one property called IdentityService, and this object has two properties, called IdentityTtlInSeconds and LookupDelayInMillis. If you are using a default serializer your classes need to reflect the structure that you have in your JSON string.
And now you can use it to deserialize your string:
var rootObject = JsonConvert.DeserializeObject<RootObject>(itemAsString);
_identityService = rootObject.IdentityService;

How to serialize the base class with derived classes

.
Hello,
I have this sample code :
public class Vehicule
{
public string Name { get; set; }
public Brand Brand { get; set; }
}
public class Car : Vehicule
{
public string Matriculation { get; set; }
}
public class Brand
{
public string Name { get; set; }
}
public class Renault : Brand
{
public string Information { get; set; }
}
If I create this instance :
var car = new Car { Name = "Clio", Matriculation = "XXX-XXX", Brand = new Renault { Name = "Renault", Information = "Contact Infos" } };
When I serialize this object like that :
var serializer = new XmlSerializer(typeof(Car), new Type[] { typeof(Renault)});
serializer.Serialize(wr, car);
I obtain this :
<?xml version="1.0" encoding="utf-8"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Clio</Name>
<Brand xsi:type="Renault">
<Name>Renault</Name>
<Information>Contact Infos</Information>
</Brand>
<Matriculation>XXX-XXX</Matriculation>
</Car>
But, in my project, I don't have to have informations on derived classes, I would like only elements of base classes from this instance like this :
var serializer = new XmlSerializer(typeof(Vehicule));
serializer.Serialize(wr, car);
The Xml :
<?xml version="1.0" encoding="utf-8"?>
<Vehicule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Clio</Name>
<Brand>
<Name>Renault</Name>
</Brand>
</Vehicule>
Can you please, help me to obtain the good Xml (only with base type Vehicule and Brand) ?
Many thanks
You can't magically serialize a derived class as it's base because
"...Serialization checks type of instance by calling Object.getType()
method. This method always returns the exact type of object."
http://bytes.com/topic/net/answers/809946-how-force-serialize-base-type
The solution here, if you really need to only serialize the base class is to implement the IXmlSerializable interface and create your own custom serializer.
IXmlSerializable:
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable(v=vs.110).aspx
One more thought. If you can work around the limitation of outputting the extra XML elements, you are able to serialize the derived class using only the base object by either 1) using XmlIncludeAttributes on the base class to tell it which types to expect or 2) using the XmlSerializer constructor overload that takes a list of types.
Edit:
After thinking about this a little more, a workaround would be that you would add a Clone() method onto your base object, then serialize the clone of the base.
LinqPad code:
public class Vehicule
{
public string Name { get; set; }
public Brand Brand { get; set; }
public Vehicule Clone()
{
return new Vehicule { Name = this.Name, Brand = new Brand { Name = this.Brand.Name } };
}
}
public class Car : Vehicule
{
public string Matriculation { get; set; }
}
public class Brand
{
public string Name { get; set; }
}
public class Renault : Brand
{
public string Information { get; set; }
}
void Main()
{
var car = new Car { Name = "Clio", Matriculation = "XXX-XXX", Brand = new Renault { Name = "Renault", Information = "Contact Infos" } };
var vehicle = car as Vehicule;
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(Vehicule));
XmlWriterSettings settings = new XmlWriterSettings
{
Encoding = new UnicodeEncoding(false, false),
Indent = false,
OmitXmlDeclaration = false
};
using(StringWriter textWriter = new StringWriter())
using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) {
serializer.Serialize(xmlWriter, vehicle.Clone());
textWriter.ToString().Dump();
}
}
This is one of the issues with inheritance, and another reason to favor composition imho.
I ran into the same issue on a mobile app where I had a Contact class that derives from ContactSummary. The repository returns Contact instances, but in lots of cases I only wanted the ContactSummary going over the wire to save on message sizes and data usage etc. The default Xml and Json serialisers would only work when the derived class was attributed with the [KnownType()] of the base class, but this still meant all those extra properties going over the wire.
Using inheritance it is problematic to achieve a viable solution, and I didn't want to resort to custom serialisers, and if the solution is to pollute the DTO with copy constructors and clone properties, then why not change the DTO to use composition instead?
If you have control over your DTOs, then restructuring them to use composition rather than inheritance may be the answer. In my example it was fairly simple...
public class ContactSummary
{
public string Name { get; set;}
public string Phone { get; set; }
}
public class Contact
{
public ContactSummary Summary { get; set; }
// ... other properties here
}
In your example, Car would need to contain a reference to Vehicle not inherit from it - something like...
[KnowTypes(typeof(Renault))]
public class Vehicle
{
public string Name { get; set; }
public Brand Brand { get; set; }
}
public class Car
{
public Vehicle Vehicle { get; set; }
public string Matriculation { get; set; }
}
Then when you want the 'base' type in your example, simply serialise Car.Vehicle.
I had the same problem and I got around it by re-mapping the inheriting class into the base class using AutoMapper:
MapperConfiguration config = new MapperConfiguration(cfg => cfg.CreateMap<Inheriting, Base>());
IMapper mapper = config.CreateMapper();
var baseObj = mapper.Map<Base>(InheritingObj);
There is not much you can customize on XmlSerializer out-of-the-box options.

Categories