generic interfaces/classes and inheritance - c#-4.0

I think I may be using generic interfaces inappropriately (but not sure so please tell me). I have a small inheritance hierarchy for horse racing. There are 3 primary interfaces : IMeeting + IRace + IRunner which I have reduced for the example. The meeting contains races which contains runners. I have used generics to make runtime decisions on the concrete types but it looks ugly, the WriteData method param has to declare the type for IMeeting which has to declare the type for IRace etc e.g.
static void WriteData(IMeeting<IRace<IRunner, string>> meeting)
Here is the little example:
class Program
{
static void Main(string[] args)
{
IMeeting<IRace<IRunner, string>> meeting = new Meeting<IRace<IRunner, string>>();
IRace<IRunner, string> slrace = new SL_Race<IRunner, string>();
IRunner slrunner = new SL_Runner();
slrace.Runners.Add(slrunner);
meeting.Races.Add(slrace);
WriteData(meeting);
}
static void WriteData(IMeeting<IRace<IRunner, string>> meeting)
{
// Write to db or whatever
}
}
public interface IMeeting<T_Race>
{
string Course { get; set; }
string CourseId { get; set; }
List<T_Race> Races { get; set; }
}
public class Meeting<T_Race> : IMeeting<T_Race>
{
public string Course { get; set; }
public string CourseId { get; set; }
public List<T_Race> Races { get; set; }
public Meeting()
{
Races = new List<T_Race>();
}
}
public interface IRace<T_Runner, T_Going>
{
T_Going Going { get; set; }
List<T_Runner> Runners { get; set; }
}
public interface ISL_Race<T_Runner, T_Going> : IRace<T_Runner, T_Going>
{
// Extended behaviour
string Time { get; set; }
string RaceId { get; set; }
string Info { get; set; }
uint MaxOR { get; set; }
}
public class SL_Race<T_Runner, T_Going> : ISL_Race<T_Runner, T_Going>
{
// IRace
public T_Going Going { get; set; }
public List<T_Runner> Runners { get; set; }
// ISL_RACE
public string Time { get; set; }
public string RaceId { get; set; }
public string Info { get; set; }
public uint MaxOR { get; set; }
public SL_Race()
{
Runners = new List<T_Runner>();
}
}
public interface IRunner
{
string Name { get; set; }
}
public class SL_Runner : IRunner
{
public string Name { get; set; }
}
In my real world app there are a few different types of concrete runner and races. I am trying to create a relevant meeting at runtime. In my mind IMeeting must have a declaration for IRaces but the concrete race type can't be known until runtime and same for the runners. My real world app also has more generic parameters and I end up with ugly looking method signatures that have to be aware of the types up the hierarchy e.g.
public List<IMeeting<IRP_Race<IRP_Runner, Going>>> ExtractMeetingList(String dayResultPage)
So am I using generics inappropriately? I could remove all generics by moving the generic properties down to concrete classes and specify them as non generic e.g. I could move IRace.Runners to the SL_Race class, but it seems to me it should be in IRace as a race interface should have runners.
Thanks for any input.
**edit - having thought about it I should probably remove the generics and just create a subclass that has the required types that will be known at compile time e.g.
public interface IMeeting
{
string Course { get; set; }
string CourseId { get; set; }
}
// This is the new subclass with the list of concrete races "ISL_RACE"
public class ISL_Meeting : IMeeting
{
List<ISL_Race> Races { get; set; }
}
public class SL_Meeting : ISL_Meeting
{
public string Course { get; set; }
public string CourseId { get; set; }
List<ISL_Race> Races {get; set;}
public SL_Meeting()
{
Races = new List<ISL_Race>();
}
}

Related

Autmapper nested mapping

I have the following main class:
public class ResearchOutcome
{
public ResearchOutcomeCategory ResearchOutcomeCategory { get; set; }
public string? UniqueIdentifier { get; set; }
}
And the category class is:
public class ResearchOutcomeCategory
{
public int Id { get; set; }
public string Name { get; set; }
public string? Description { get; set; }
}
The View models for above classes are:
public class ResearchOutcomeDetailVm : IMapFrom<ResearchOutcome>
{
public int Id { get; set; }
public virtual ResearchOutcomeCategoryDetailVm ResearchOutcomeCategory { get; set; }
}
public class ResearchOutcomeCategoryDetailVm : IMapFrom<ResearchOutcomeCategory>
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
Now, I have used the following mapping profile:
// First this one
profile.CreateMap<ResearchOutcomeCategory, ResearchOutcomeCategoryDetailVm>();
profile.CreateMap<ResearchOutcome, ResearchOutcomeDetailVm>();
//Then I tried this one
profile.CreateMap<ResearchOutcome, ResearchOutcomeDetailVm>()
.ForMember(o => o.ResearchOutcomeCategory,
cat => cat.MapFrom( o => o.ResearchOutcomeCategory));
But the ResearchOutcomeCategory is always null. Any help would be appreciated.
After digging more, I identified that I was not "Including" the relevant item in the query, hence, the view model was always empty. Pretty dumb on my part :D
Regarding the mapping, if the properties (even complex ones) have the same names, then the mapper will map them automatically. So simply this line worked
profile.CreateMap<ResearchOutcomeCategory, ResearchOutcomeCategoryDetailVm>();
Hope it helps someone

can the parameters FromUri be read from an attribute?

I have a simple controller that accepts a response from a payment system.
public async Task<IHttpActionResult> Pending([FromUri] DepositResponse response)
{
Logger.LogInfo(JsonConvert.SerializeObject(response));
return Ok(response);
}
the deposit response however has very ugly and unstandardised parameters. I have no control over that because that's what the payment system sends.
public class DepositResponse
{
public string ppp_status { get; set; }
public string ExErrorCode { get; set; }
public string PPP_TransactionID { get; set; }
public string merchant_site_id { get; set; }
//etc
}
As a result, Resharper complains about the chosen name that it doesn't match the rules and I want to change it to match all the classes in the rest of the project.
Is there an attribute I can use, or one I can create to make FromUri understand the response?
For example
public class DepositResponse
{
[FromUriName("ppp_status")]
public string pppStatus { get; set; }
[FromUriName("ExErrorCode")]
public string exErrorCode { get; set; }
[FromUriName("PPP_TransactionID")]
public string pppTransactionId { get; set; }
[FromUriName("merchant_site_id")]
public string merchantSiteId { get; set; }
//etc
}
I couldn't find such an example online, but I would imagine it can be very useful when dealing with external systems that send rubbish...
any ideas?
You can use the below model
public class DepositResponse
{
[JsonProperty(PropertyName="ppp_status")]
public string pppStatus { get; set; }
[JsonProperty(PropertyName="ExErrorCode")]
public string exErrorCode { get; set; }
[JsonProperty(PropertyName="PPP_TransactionID")]
public string pppTransactionId { get; set; }
[PropertyName(PropertyName="merchant_site_id")]
public string merchantSiteId { get; set; }
//etc
}

SchemaBuilder with complex types

I want to store complex content part record but couldn't create columns with SchemaBuilder in Migrations file.
Here are my classes:
public enum BoxInheritance
{
Empty, Inherit, Enter
}
public class BoxSize
{
public string Width { get; set; }
public string Height { get; set; }
}
public class BoxSpace
{
public string Left { get; set; }
public string Right { get; set; }
public string Top { get; set; }
public string Bottom { get; set; }
}
public class BoxPartRecord : ContentPartRecord
{
public virtual BoxSize Size { get; set; }
public virtual BoxSpace Space { get; set; }
public virtual Dictionary<string, BoxInheritance> Inheritances { get; set; }
public BoxPartRecord()
{
Size = new BoxSize();
Space = new BoxSpace();
Inheritances = new Dictionary<string, BoxInheritance>();
}
}
Is it ok to use a content part record like this?
How to create a table for this content part record?
I think this won't work. My suggestion is to use simple types in the record class and complex types in the content part itself (you can do the mapping there).
public class BoxPartRecord
{
public virtual int Width { get; set; }
public virtual int Height { get; set; }
...
}
public class BoxPart : ContentPart
{
public BoxSize Size { get { return new BoxSize {record.Width, record.Height} ...
}

Why does this ploymorphic List property go null when adding additional objects to the list?

Consider the following:
public class VideoContainer<T>
{
public string Name { get; set; }
//public List<VideoContainer<T>> VideoContainers { get; set; }
}
public class Perspective : VideoContainer<Perspective>
{
public List<VideoContainer<SourceContainer>> VideoContainers { get; set; }
}
I want to ensure VideoContainer<Perspective>.VideoContainers can only contain VideoContainer<SourceContainer> types.
I add a new Perspective object to a List<Perspective> with three VideoContainers. The problem is that when I add a new Perspective to the list, the previously-added Perspective.VideoContainers is null.
Why is this happening?
It sounds like you need two generic types:
public class VideoContainer<T, U>
{
public string Name { get; set; }
public List<VideoContainer<U>> VideoContainers { get; set; }
}
public class Perspective : VideoContainer<Perspective, SourceContainer>
{
// No longer declare the list, just use it... it's now:
// public List<VideoContainer<SourceContainer>> VideoContainers { get; set; }
}

AutoMapper - How to map a concrete domain class to an inherited destination DTO class?

I have a flat domain class like this:
public class ProductDomain
{
public int ID { get; set; }
public string Manufacturer { get; set; }
public string Model { get; set; }
public string Description { get; set; }
public string Price { get; set; }
}
I have two DTO classes like this:
public class ProductInfoDTO
{
public int ID { get; set; }
public string Manufacturer { get; set; }
public string Model{ get; set; }
}
public class ProductDTO : ProductInfoDTO
{
public string Description { get; set; }
public string Price { get; set; }
}
Now the problem is:
Scenario #1:
Mapper.CreateMap<ProductDomain, ProductInfoDTO>() // this mapping works fine
Scenario #2:
Mapper.CreateMap<ProductDomain, ProductDTO>() // this mapping is not working and throws System.TypeInitializationException
So my question is how to create mapping between ProductDomain and ProductDTO (which inherits ProductInfoDTO) without breaking the definition of both source and destination classes. Also I dont want to introduce any new inheritance for the domain class ProductDomain.
Thanks
You can build your own custom TypeConverter like this
public class ProductDomainToProductDTOConverter : ITypeConverter<ProductDomain, ProductDTO>
{
public ProductDTO Convert(ProductDomain source)
{
ProductDTO product = new ProductDTO();
product.Price = source.Price;
...
return product;
}
}
And then create a map with your custom TypeConverter like this
Mapper.CreateMap<ProductDomain, ProductDTO>().ConvertUsing<ProductDomainToProductDTOConverter>();

Resources