Jil.DeserializationException : Error occurred building a deserializer in redis cache - c#

I'm using Redis Cache using Stack Exchange library.
I used cloudStructure library to use Redis Dictionary and Redis List.
Problem is when I try to retrieve values and if that model has a null
value for one list property it is throwing me below exception -
Jil.DeserializationException : Error occurred building a deserializer
for TestMainClass: Expected a
parameterless constructor for
System.Collections.Generic.ICollection1[TestChildClass]
---- Jil.Common.ConstructionException : Expected a parameterless constructor for
System.Collections.Generic.ICollection1[TestChildClass]
public class TestMainClass
{
public TestMainClass();
public int Id { get; set; }
public virtual ICollection<TestChildClass> Mydata { get; set; }
public string Title { get; set; }
}
public class TestChildClass
{
public TestChildClass();
public int Id { get; set; }
public string Value { get; set; }
}
Redis code for retrieve value:
RedisDictionary<int, TestMainClass> dictionary =
new RedisDictionary<int, TestMainClass>("localhost", "mylocaldictionary");
var result = await dictionary.Get(121);
What If I could not able to convert ICollection < T > into List < T >?

It might be a nice feature if the serialization library detected interfaces like ICollection<T> and IList<T> and implemented them with the concrete List<T> during deserialization, but ultimately: every feature needs to be thought of, considered (impact), designed, implemented, tested, documented and supported. It may be that the library author feels this is a great idea and should be implemented; it might not be high on the author's list, but they'd be more than happy to take a pull request; or there might be good reasons not to implement it.
In the interim, as a general rule that will solve virtually every serialization problem you will ever encounter with any library:
the moment the library doesn't work perfectly with your domain model: stop serializing your domain model - use a DTO instead
By which, I mean: create a separate class or classes that are designed with the specific choice of serializer in mind. If it wants List<T>: then use List<T>. If it wants public fields: use public fields. If it wants the types to be marked [Serializable]: mark the types [Serializable]. If it wants all type names to start with SuperMagic: then start the type name with SuperMagic. As soon as you divorce the domain model from the serialization model, all the problems go away. In addition: you can support multiple serializers in parallel, without getting into the scenario that A needs X and doesn't work with Y; B needs Y and doesn't work with X.
All you then need to do is write a few lines of code to map between the two similar models (or use libraries that do exactly that, like AutoMapper).

Related

Create and use covariant and mutable list (or potential workaround)

I'm currently modifying a Blazor library and the souce code of the current state is available on gitlab.
My situation is as follows:
I have a LineChartData object which is supposed to store multiple Datasets for LineCharts.
These Datasets intern have a List of Data. Instead of just working with List<object> I wanted to be able to have List<TData>.
Because there is a Mixed Chart which can accept both LineChartDatasets and BarChartDatasets, there is an interface called IMixableDataset.
I started by making this interface generic so it now looks like this (simplified):
public interface IMixableDataset<TData>
{
List<TData> Data { get; }
}
I then made my implementing class (LineChartDataset) generic as well and it now looks like this (simplified):
public class LineChartDataset<TData> : IMixableDataset<TData>
{
public List<TData> Data { get; }
}
Next up was LineChartData. I first made this generic as well and continued with that until I reached the top level (see current state of my master branch). However I later wanted to change this because I wanted to support multiple Datasets with different kind of values. For this reason I reverted the generic stuff in all classes "above" the Datasets and the LineChartData now looks like this (simplified):
public class LineChartData
{
// HashSet to avoid duplicates
public HashSet<LineChartDataset<object>> Datasets { get; }
}
I decided to go with LineChartDataset<object> because: Since everything is castable to object, (in my mind) XYZ<Whatever> should also be castable to XYZ<object> but as I learned, this is not the case.
The where keyword didn't help either since I don't want to enforce TData to have relations apart from object - it could be int, string or something completely different. The only relation these LineDatasets are supposed to have is that they are LineDatasets, not what type they contain.
I then learned about Covariance and Contravariance (out and in-keyword). I tried out to make TData in IMixableDataset covariant but since List and IList/ICollection are all invariant I was unable to persue.
I also read about IReadOnlyCollection<> which is covariant but I cannot use this because I have to be able to modify the list after creation.
I have also tried using implicit/explicit operators to convert LineChartDataset<whatever> to LineChartDataset<object> but this has a few issues:
Since I created a new instance, I would need to store and use the new instance instead of the original one to add items, completely destroying the typesafety I had with the original one.
Since there are many more properties in LineChartDataset I would have to clone all of them as well.
If there is a way to convert a more specific one to the other while preserving the instance and not having to write code for every property this might be a solution.
Complete sample which reproduces the error I get and shows the issue:
// Provides access to some Data of a certain Type for multiple Charts
public interface IMixableDataset<TData>
{
List<TData> Data { get; }
}
// Contains Data of a certain Type (and more) for a Line-Chart
public class LineChartDataset<TData> : IMixableDataset<TData>
{
public List<TData> Data { get; } = new List<TData>();
}
// Contains Datasets (and more) for a Line-Chart
// This class should not be generic since I don't want to restrict what values the Datasets have.
// I only want to ensure that each Dataset intern only has one type of data.
public class LineChartData
{
// HashSet to avoid duplicates and Public because it has to be serialized by JSON.Net
public HashSet<LineChartDataset<object>> Datasets { get; } = new HashSet<LineChartDataset<object>>();
}
// Contains the ChartData (with all the Datasets) and more
public class LineChartConfig
{
public LineChartData ChartData { get; } = new LineChartData();
}
public class Demo
{
public void DesiredUseCase()
{
LineChartConfig config = new LineChartConfig();
LineChartDataset<int> intDataset = new LineChartDataset<int>();
intDataset.Data.AddRange(new[] { 1, 2, 3, 4, 5 });
config.ChartData.Datasets.Add(intDataset);
// the above line yields following compiler error:
// cannot convert from 'Demo.LineChartDataset<int>' to 'Demo.LineChartDataset<object>'
// the config will then get serialized to json and used to invoke some javascript
}
public void WorkingButBadUseCase()
{
LineChartConfig config = new LineChartConfig();
LineChartDataset<object> intDataset = new LineChartDataset<object>();
// this allows mixed data which is exactly what I'm trying to prevent
intDataset.Data.AddRange(new object[] { 1, 2.9, 3, 4, 5, "oops there's a string" });
config.ChartData.Datasets.Add(intDataset); // <-- No compiler error
// the config will then get serialized to json and used to invoke some javascript
}
}
The reason everything only has getters is because of my initial attempt with using out. Even thought this didn't work out, I learned that you usually don't expose Setters for Collection-properties. This is not fix and also not very important for the question but I think worth mentioning.
Second complete example. Here I'm using out and an IReadOnlyCollection. I have removed the descriptions of the class (already visible in the previous example) to make it shorter.
public interface IMixableDataset<out TData>
{
IReadOnlyCollection<TData> Data { get; }
}
public class LineChartDataset<TData> : IMixableDataset<TData>
{
public IReadOnlyCollection<TData> Data { get; } = new List<TData>();
}
public class LineChartData
{
public HashSet<IMixableDataset<object>> Datasets { get; } = new HashSet<IMixableDataset<object>>();
}
public class LineChartConfig
{
public LineChartData ChartData { get; } = new LineChartData();
}
public class Demo
{
public void DesiredUseCase()
{
LineChartConfig config = new LineChartConfig();
IMixableDataset<int> intDataset = new LineChartDataset<int>();
// since it's ReadOnly, I of course can't add anything so this yields a compiler error.
// For my use case, I do need to be able to add items to the list.
intDataset.Data.AddRange(new[] { 1, 2, 3, 4, 5 });
config.ChartData.Datasets.Add(intDataset);
// the above line yields following compiler error (which fairly surprised me because I thought I correctly used out):
// cannot convert from 'Demo.IMixableDataset<int>' to 'Demo.IMixableDataset<object>'
}
}
So the question:
Is there anyway to have a mutable and covariant collection?
If not, is there a workaround or something I can do to achieve this functionality?
Additional stuff:
I'm using the newest version of everything (.net core, VS, blazor, C#). Since the library is .NET Standard I'm still on C# 7.3 there.
In the repo under WebCore/Pages/FetchData you can perfectly see what I want to achieve (see comments at the end of the file).
Looking more closely at your example, I see one major problem: you are attempting to involve value types (e.g. int) in type variance. For better or worse, C# type variance applies only to reference types.
So, no…sorry, but it is quite impossible to do exactly what you're asking. You would have to represent all value-type based collections as object, not as their specific value types.
Now, as far as reference-type collections go, your example will work fine, with one minor change. Here's a modified version of your second example showing it working, with that one minor change:
public interface IMixableDataset<out TData>
{
IReadOnlyCollection<TData> Data { get; }
}
public class LineChartDataset<TData> : IMixableDataset<TData>
{
private readonly List<TData> _list = new List<TData>();
public IReadOnlyCollection<TData> Data => _list;
public void AddRange(IEnumerable<TData> collection) => _list.AddRange(collection);
}
public class LineChartData
{
public HashSet<IMixableDataset<object>> Datasets { get; } = new HashSet<IMixableDataset<object>>();
}
public class LineChartConfig
{
public LineChartData ChartData { get; } = new LineChartData();
}
public class Demo
{
public void DesiredUseCase()
{
LineChartConfig config = new LineChartConfig();
// Must use reference types to take advantage of type variance in C#
LineChartDataset<string> intDataset = new LineChartDataset<string>();
// Using the non-interface method to add the range, you can still mutate the object
intDataset.AddRange(new[] { "1", "2", "3", "4", "5" });
// Your original code works fine when reference types are used
config.ChartData.Datasets.Add(intDataset);
}
}
In particular, note that I've added an AddRange() method to your LineChartDataset<TData> class. This provides a type-safe way to mutate the collection. Note that the code that wants to mutate the collection must know the correct type, bypassing the variance restrictions.
The variant interface IMixableDataset<TData> itself cannot, of course, include a way to add things, because this would not be type-safe. You would be able to treat your LineChartDataset<string> as a IMixableDataset<object>, and then if you could add things via that interface, you'd be able to add some other type of object, even a non-reference type like a boxed int value, to your collection that's supposed to only contain string objects.
But, just as the invariant List<T> can implement the covariant IReadOnlyCollection<T>, your concrete LineChartDataset<TData> class can implement IMixableDataset<TData> while still providing a mechanism for adding items. This works because while the concrete type determines what the object can actually do, the interfaces simply define a contract that users of the reference must abide by, allowing the compiler to ensure type safety where the interface is used, even when used in a variant way. (The invariant concrete type ensures type safety as well, but only because the type has to match exactly, which is of course more restrictive/less flexible.)
If you don't mind using object in place of any specific value type for the value-type-based collections, then the above would work. It's a bit clumsy, since any time you actually want to get the value type values out, you'd need to retrieve them as object and then cast as necessary to actually use them. But at least the broader variant approach would then succeed, and no special handling would be required for any reference types.
Aside: that type variance in C# is restricted to reference types is based on the pragmatic requirement that type variance doesn't affect the runtime code. It's just a compile-time type-conversion. This means that you have to be able to just copy references around. To support value types would require adding new boxing and unboxing logic where it otherwise wouldn't exist. It's also not quite as useful, because value types don't have the same rich degree of type inheritance that reference types can have (value types can only ever inherit object, so variant scenarios are much less useful and interesting, in general).

Dynamically ignore data members from getting serialized

We have an existing WCF service which uses several DataContracts. We want to modify the serialization based on the device, so that when accessed from mobile devices, the service should serialize only some important data members(not all)
We have 2 options here
Create separate operation and data contracts for different types of
devices
Mess with the actual xml serialization and suppress creating
unnecessary elements based on the device
We don't want to go with the first option since it introduces a lot of redundant code problems in the future
Small research showed that we need to use IXmlSerializable and override the readXML() and writeXML() methods. But at the same time, I have seen somewhere that DataContract and IXmlSerializable should not be used together
Any example to mess with actual serialization is greatly appreciated .
[DataContract]
public class TokenMessage
{
string tokenValue;
string extraValue;
[DataMember]
public string Token
{
get { return tokenValue; }
set { tokenValue = value; }
}
[DataMember]
public string Extra
{
get { return extraValue; }
set { extraValue = value; }
}
}
Now when i access the service which returns a typical TokenMessage data contract, from a mobile device, i don't want the "Extra" data member to be serialized i.e. When I supply a different argument to the operation contract, it should be able to serialize some/all the data members(depending on the action)
PS: For now please ignore the device detection part. Lets assume we have an argument in the operation contract, which helps us identify the device
I'm not convinced that some variant of #Pranav Singh's answer isn't a better design, but that's not your question...
As you mentioned in a comments attributes in .NET are static by design. This means dynamically adding/removing [DataMember] isn't a good option. It is possible. There are options like using Reflection.Emit to recreate the instance with the meta data changes (see all the answers to Can attributes be added dynamically in C#?) but all of those routes are complicated.
I see two reasonable options:
1) Implement an IParameterInspector for the service. In the AfterCall() method you could inspect and alter the parameters being returned to the client before they are serialized. There is some work to use reflection to dynamically determine the parameter types and set their values, but its not complicated. This is the better design that enables reuse of the behavior across many contracts or services. Carlos Figueira's blog is the best source for WCF extension examples.
2) Use the [OnSerializing] and [OnSerialized] events. In the [DataContract] you could temporarily alter what the properties are returning during serialization. The events are actually designed to enable initialization and as such this solution is a bit of a hack. This solution is also not thread safe. But it does keep the code contained to the DataContract class and solves the problem quickly (and I think you are looking for quick).
Solution #2 mights look something like:
[DataContract]
public class TokenMessage
{
string tokenValue;
string extraValue;
bool enableExtraValue = true;
[DataMember]
public string Extra
{
get {
if (enableExtraValue)
return extraValue;
return null;
}
set { extraValue = value; }
}
[OnSerializing()]
internal void OnSerializingMethod(StreamingContext context)
{
enableExtraValue = false;
}
[OnSerialized()]
internal void OnSerializedMethod(StreamingContext context)
{
enableExtraValue = true;
}
}
Solution #2 is a quick fix (which is what I think you are looking for).
Solution #1 is the better design.
Try using IgnoreDataMemberAttribute
There is a approach, but I think this will require extra DataContract to be generated but still no need for separate operation and data contracts for different types of devices.
It can classic implementation to run-time polymorphism. I am just giving idea:
Say you have a generic DataContract like :
[DataContract]
[KnownType(typeof(Extra))]
[KnownType(typeof(Extra2))]
public class TokenMessage
{
string tokenValue;
string extraValue;
[DataMember]
public string Token
{
get { return tokenValue; }
set { tokenValue = value; }
}
}
Other device specific contracts can inherit TokenMessage as base class like:
[DataContract]
public class Extra:TokenMessage
{
[DataMember]
public string Extra
{
get ;set;
}
}
[DataContract]
public class Extra2:TokenMessage
{
[DataMember]
public string Extra2
{
get ;set;
}
}
Now at run-time as you say you know an argument in the operation contract, which helps us identify the device. Say based on device type, you can instantiate base class with derived class like:
TokenMessage tm= new Extra();
OR
TokenMessage tm= new Extra2();
So at run-time you will decide which device contract will be part of genric response.
Note: Adding KnownType will generate the separate xsd within wsdl for all known types within base class, but saves serialization for data at run-time as this should depend on actual inheritance chosen.
In your model add a property 'ShouldSerializeYOUR_PROPERTY_NAME', set it to false when you do not want the property serialized.
See more here: http://msdn.microsoft.com/en-us/library/system.windows.dependencyobject.shouldserializeproperty(v=vs.110).aspx

InvalidCastException while no compile errors with upcasting

What I'm basically trying to do is Convert Objects I get from a web Service to objects that are compatible with my Entity Framework object. I though of doing this by creating an Interface that both is applied to the web service objects & the EF objects. That way I can easily cast from one type to the other.
At this point I have the following object: A, A1, B and interface IAB.
The problem I'm no facing is when I do an upcast from object A to A1 I get a Run-time error but no compile errors. I would like to know why my upcast isn't accepted?
public class A
{
//Has variables & Properties
}
public class A1 : A, IAB
{
//Has some properties
}
Note: I needed to create A1 as extending the partial class A created Serialization problems for the web service. So this seemed to be the best solution.
When contacting the service I ask for a list of A objects and then want to upcast them to A1. Later I will cast them into B.
I try to cast the objects like this:
List<A1> allA1 = new List<A1>();
foreach (A item in retrievedListOfA)
{
allA1.Add((A1)item);
}
As I don't get any compile errors I find it strange that I get this error. if I do a check of the type "A is A1" then it never goes in that if statement.
Can someone point out to me why this is creating problems? Is it because object A is from a web service?
Note: If this method of "Porting" object from one to another is totally absurd please give me some directions how it should be done. It is the first time I'm attempting something like this.
You don't get any compile errors, because (A1)item, is you saying to the compiler, I know what I'm doing so shut up.
So if retrievedListOfA is a collection of As and A1s, every A you cast to an A1, that is in fact an A and then call an A1 method on will blow up.
There are lots of porting methods, e.g. a converter, casting is not one of them.
Tony Hopkinson's answer is right about the reason you are getting the current error. But, it does not currently address the larger issue you hint at.
Quote: Oxillery
Note: If this method of "Porting" object from one to another is totally absurd
pleasegive me some directions how it should be done. It is the first time I'm attempting
something like this.
It appears that you are receiving a collection of serialized class instances (from a web service), and want to make them into entity framework compatible objects. I believe your issues arise because there is inconsistency between the serialization and deserialization of your instances.
Take the following simple class (our desired Entity Framework entity):
public class Dog
{
/// <summary>
/// The unique ID of this dog, aka the number printed on the dog's implanted microchip.
/// </summary>
[Key]
public int Id { get; set; }
public DateTime Birthday { get; set; }
public string Name { get; set; }
/// <summary>
/// The embarassing number of homeworks shredded.
/// </summary>
public long ShreddedHomeworks { get; set; }
}
Based on your statement, you are receiving from a web service some kind of other object that you want to convert to a Dog. Suppose the class that you are receiving looks like the following:
public class PseudoDog
{
public DateTime Birthday { get; set; }
public string Name { get; set; }
public int Legs { get; set; }
}
Notice that that the two classes are not directly compatible in terms of serializing a PseudoDog and deserializing it as a Dog. I purposely made the PseudoDog have 'Legs' as a property and Dog have 'ShreddedHomeworks' so that without manipulation, they cannot be converted.
The basis for how they can be converted is from the Web API tutorial about data transfer objects (DTO's) and their use. Continuing the example above, the class used to convert a PseudoDog to a Dog would look like the following:
using System.Runtime.Serialization;
[DataContract]
public class DogDTO
{
#region Static Methods
public static Dog ToDog(DogDTO dto)
{
// if the data transfer object is null
// we cannot make a Dog from it.
if (dto == null)
{
return null;
}
Dog dog = new Dog();
// We can be sure of what these values are intended to be.
dog.Name = dto.Name;
dog.Birthday = dto.Birthday;
return dog;
}
public static DogDTO CreateFrom(Dog dog)
{
if (dog == null)
{
return null;
}
DogDTO dto = new DogDTO();
dto.Name = dog.Name;
dto.Birthday = dog.Birthday;
}
#endregion
[DataMember]
public DateTime Birthday { get; set; }
[DataMember]
public string Name { get; set; }
}
The juicy bits of DogDTO are two properties at the bottom (Birthday and Name) which have the DataMember attribute. This means that the DogDTO class can be serialized and deserialized with the DataContractSerializer.
Putting all the pieces together, the entire process looks like this:
Some client makes a PseudoDog instance named 'Fido'
The client serializes 'Fido' (to XML, JSON, binary, etc...) to file named 'serialdog.xml'.
The client sends the webservice the 'serialdog.xml' file.
The webservice that receives 'serialdog.xml' deserializes it into a DogDTO instance (named 'FidoDTO')
Your method calls DogDTO.ToDog(FidoDTO) which returns a new Dog instance named 'myFido'.
You can now use the Dog instance 'myFido' as it is an Entity Framework entity.
Succintly, conversion goes like this:
Web Service object --> object DTO --> Entity Framework compliant object
Under the following assumptions that
Type A - the Type of the instance from web service
Type A1 - the Type of your current conversion instance
Type B - the Type of the instance used by Entity Framework
and
Type A_DTO - the Type of the data transfer object
You should make the following changes wherever it is you have this code:
List<A1> allA1 = new List<A1>();
foreach (A item in retrievedListOfA)
{
allA1.Add((A1)item);
}
I would replace it with this:
List<B> allB = new List<B>();
foreach (A_DTO dto in retrievedListofA_DTO)
{
allB.Add(A_DTO.ToB(dto));
}

encapsulating method for list of objects

I have a class that looks like this:
public class MyModel{
public int TheId { get; set; }
public int ....
public string ....
}
I have another class that take a list of several types, including MyModel, and serializes the lists in json. It has several methods, one for each type of list.
public class ToJson{
public string MyModelToJson (List<MyModel> TheListOfMyModel) {
string ListOfMyModelInJson = "";
JavascriptSerializer TheSerializer = new ....
TheSerializer.RegisterConverters(....
ListOfMyModelInJson = TheSerializer.Serialize(TheListOfMyModel);
return ListOfMyModelInJson;
}
public string MyOtherModelToJson (List<MyOtherModel> TheListOfOtherModel) {....}
public string YetAnotherModelToJson (List<YetAnotherModelToJson> TheListOfYetAnotherModelToJson) {....}
}
What I want to do is encapsulate the serializing into MyModel, something like this:
public class MyModel{
public int TheId { get; set; }
public int ....
public string ....
public string MyModelToJson()
}
How can I encapsulate a method into an object so that it's available for a list of objects?
I thought of doing a foreach loop but that gets messy because in the calling method, you have to manipulate the json strings of each object in the list and concatenate them.
Let me know of OO principles of encapsulation apply in this case.
Thanks for your suggestions.
One way would be to define your ToJson as accepting a generic type:
public class ToJson<T>{
public string MyModelToJson (List<T> TheListOfMyModel) {
string ListOfMyModelInJson = "";
JavascriptSerializer TheSerializer = new ....
TheSerializer.RegisterConverters(....
ListOfMyModelInJson = TheSerializer.Serialize(TheListOfMyModel);
return ListOfMyModelInJson;
}
}
extension methods!
public static class JsonExtensions
{
public static string ToJson<T>(this List<T> list)
{
}
}
I'm not sure that I understand your question, but I think that what you want to do is not return a String but a JsonObject, JsonArray, or JsonPrimitive:
public class MyModel {
public JsonObject myModelToJson() ... //this method implements the interface!
}
Where JsonObject is a class that represents a json object.
Make this class implement an interface where the contract is that the return value is a JsonValue.
Then, in the ToJson class, return a JsonArray:
public class ToJson
public JsonArray myModelToJson(List<things that can be json-ized> myList) ...
}
Don't serialize the objects/arrays/primitives to a String until you absolutely need to, and let a library take care of the actual serialization.
That was a confusing answer.
Here's what I think you should do:
get hold of a decent json library. Ideally, it should have JsonObjects, JsonArrays, and JsonPrimitives which are subclasses of JsonElement. I've used Google gson in java, but I don't know what an equivalent C# version would be.
create an interface, JsonAble with one method -- toJson -- that returns a JsonElement.
implement this interface for all concerned classes
serializing a list of JsonAble objects is then very easy -- it becomes a JsonArray.
a decent json library should have a serialize method -- so you'll never have to worry about throwing strings around yourself
For what it's worth, I wouldn't remove the class at all. What you're talking about doing is adding an additional responsibility to your model, and apparently going against SRP heuristic. That is, you have a class whose current responsibility is to model data, and you're going to make it responsible for modeling data and also converting its data to some form, using various service classes that it now needs to know about. If the model class encapsulates GUI concepts like raising events for GUI, then it has divergent reasons to change - if the scheme for notifying the GUI changes and if the scheme for converting to JSON changes.
If it were me, I'd have the models inherit from a base class or define an interface as mentioned by Matt Fenwick, and have your ToJson class take a batch of those as input, process them, and return the result.
I understand the desire to eliminate the extra class, and might advocate it if it were a simple conversion involving only data elements of the class, but as soon as you need a service class of some kind to do the operation, it seems a poor fit for the model object, as you now cannot model data without a JavascriptSerializer. That's awkward if you want to model data that you don't then serialize.
One final thing that I can think of is that you can build on a'b'c'd'e'f'g'h's suggestion and piggy back the method onto some existing service, thus eliminating the class. If you just have a generic method on that service that implements the serialization, you can eliminate the separate class, since you no longer need a separate method for each model object type.

c# DAL - Interface for business objects

I have a Report Interface which has a Run method.
There are different types of reports which implement this interface and each run their own kind of report, getting data from different tables.
Each report, using its own data context, gets data which then populates Business Objects with and at the moment they are returned as an array (I would like to be able to at least return something like a list but because you have to define the list type it makes it a bit more difficult).
Reflection is then used to find out the properties of the returned data.
I hope I have explained this well enough!
Is there a better way of doing this?
By request:
public interface IReport
{
int CustomerID { get; set; }
Array Run();
}
public class BasicReport : IReport
{
public int CustomerID { get; set; }
public virtual Array Run()
{
Array result = null;
using (BasicReportsDataContext brdc = new BasicReportsDataContext())
{
var queryResult = from j in brdc.Jobs
where j.CustomerID == CustomerID
select new JobRecord
{
JobNumber = j.JobNumber,
CustomerName = c.CustomerName
};
result = queryResult.ToArray();
}
}
}
The other class then does a foreach over the data, and uses reflection to find out the field names and values and puts that in an xml file.
As it stands everything works - I just can't help thinking there is a better way of doing it - that perhaps my limited understanding of C# doesn't allow me to see yet.
Personnally I would first ask myself if I Really need an interface. It would be the case if the classes implementing it are Really different by nature (not only by report kind).
If not, i.e all the implementing classes are basically "Reporters", then yes, there is a more convenient way to do this which is :
Writing a parent abstract Report
Having a virtual Run method and the CustomerID accessor
inheriting your "Reporter" classes from it

Categories

Resources