We're currently refactoring our ASP.NET 4.0 Web Application to run on both plain old IIS and Azure. For the Settings (in the Properties namespace), I'd like to implement the State Pattern with an AzureSettingsState and a StandaloneSettingsState, which both provide settings getter methods.
Now could anybody help me figuring out how ASP.NET deserializes the non-String values (e.g. TimeSpan or StringCollection), so that I can deserialize them on my own in the context class? All settings seem to be strings there.
public abstract class ConfigStateBase
{
public abstract string GetSettingValue(string setting);
}
I've done something like this, still don't know if it works :D
public class AzureConfig:StandaloneConfig
{
protected override string GetAppSetting(string name)
{
return RoleEnvironment.GetConfigurationSettingValue(name);
}
protected override string GetConnectionString(string name)
{
return RoleEnvironment.GetConfigurationSettingValue(name);
}
}
public class StandaloneConfig
{
public IndexedSetting AppSettings { get; private set; }
public IndexedSetting ConnectionStrings { get; private set; }
public StandaloneConfig()
{
AppSettings = new IndexedSetting(GetAppSetting);
ConnectionStrings = new IndexedSetting(GetConnectionString);
}
protected virtual String GetAppSetting(String name)
{
return ConfigurationManager.AppSettings[name];
}
protected virtual String GetConnectionString(String name)
{
var cs = ConfigurationManager.ConnectionStrings[name];
if (cs != null)
return cs.ConnectionString;
else
return null;
}
public class IndexedSetting
{
Func<String, String> _getParameter;
public IndexedSetting(Func<String,String> getParameter)
{
_getParameter = getParameter;
}
public String this[String name]
{
get { return _getParameter(name); }
}
}
Don't forget to tell Azure to use it!
static AzureConfig _config = new AzureConfig();
void Application_Start(object sender, EventArgs e)
{
Microsoft.WindowsAzure.CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
configSetter(_config.AppSettings[configName]);
});
}
If you use it let me know, I wanna get paid ... I mean I wanna know if it works :D
Related
Is there some way of build a class from a external builder class without letting their setters public? I don't want to allow a invalid instance of a class to exist without the necessary validations.
The only way I found so far is creating a constructor with the required parameters and validations.
I made a example with few properties to be filled, but imagine a case with various.
public class Computer
{
public string Motherboard { get; private set; }
public string RamMemory { get; private set; }
public string Cpu { get; private set; }
public Computer(string motherboard, string ramMemory, string cpu)
{
ValidateMotherboard(motherboard);
ValidateRamMemory(ramMemory);
ValidateCpu(cpu);
Motherboard = motherboard;
RamMemory = ramMemory;
Cpu = cpu;
}
private void ValidateMotherboard(string motherboard)
{
if (motherboard == null)
throw new ArgumentNullException(nameof(motherboard));
}
private void ValidateRamMemory(string ramMemory)
{
if (ramMemory == null)
throw new ArgumentNullException(nameof(ramMemory));
}
private void ValidateCpu(string cpu)
{
if (cpu == null)
throw new ArgumentNullException(nameof(cpu));
else if (!cpu.ToLower().Contains("ryzen"))
throw new ArgumentException("Only AMD Ryzen CPU's is good enough.");
}
}
public class ComputerBuilder
{
private string _motherboard;
private string _ramMemory;
private string _cpu;
public ComputerBuilder SetMotherboard(string motherboard)
{
_motherboard = motherboard;
return this;
}
public ComputerBuilder SetRamMemory(string ramMemory)
{
_ramMemory = ramMemory;
return this;
}
public ComputerBuilder SetCpu(string cpu)
{
_cpu = cpu;
return this;
}
public Computer Build() => new Computer(_motherboard, _ramMemory, _cpu);
}
I just want to have builders that easies the construction of classes with too much parameters. Any ideias of how do this putting the validations on the builder without allow a invalid instance to exist?
I want to change the connection to a database at runtime in a REST Api. I want to put a variable of the request and let the Api decide which connectionstring to use.
For example:
I put the variable "dbid" with the value "develop" in the request header and send it to the Api.
The Api sees the header and gets the correct connectionstring from the web.config.
I have three layers (data, business, api). The data contains EntityFramework to get and set data. Like this:
public class WebsiteContext : IocDbContext, IWebsites
{
public DbSet<Website> Websites { get; set; }
public IEnumerable<Website> GetAll()
{
return Websites.ToList();
}
}
(IoCDbContext.cs)
public class IocDbContext : DbContext, IDbContext
{
public IocDbContext() : base("develop")
{
}
public void ChangeDatabase(string connectionString)
{
Database.Connection.ConnectionString= connectionString;
}
}
In the business I have a class to retrieve data from the datalayer and do some logical stuff (not needed here, but still good for the story).
public class Websites : IWebsites
{
private readonly Data.Interfaces.IWebsites _websiteContext;
#region Constructor
public Websites(Data.Interfaces.IWebsites websiteContext)
{
_websiteContext = websiteContext;
}
#endregion
#region IWebsites implementation
public IEnumerable<Website> GetWebsites()
{
List<Data.Objects.Website> websiteDtos = _websiteContext.GetAll().ToList();
return websiteDtos.Select(web => web.ToModel()).ToList();
}
#endregion
}
public static class WebsiteMapper
{
public static Website ToModel(this Data.Objects.Website value)
{
if (value == null)
return null;
return new Website
{
Id = value.Id,
Name = value.Name
};
}
}
And, last but not least, the controller:
public class WebsiteController : ApiController
{
private readonly IWebsites _websites;
public WebsiteController(IWebsites websites)
{
_websites = websites;
}
public IEnumerable<Website> GetAll()
{
return _websites.GetWebsites().ToList();
}
}
My Unity configuration:
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<Business.Interfaces.IWebsites, Websites>();
container.RegisterType<IDbContext, IocDbContext>();
container.RegisterType<IWebsites, WebsiteContext>();
// e.g. container.RegisterType<ITestService, TestService>();
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
So as you can see the connection string with the name "develop" is used by default. This will return a website with the name "website". Now I would change the header variable "dbid" to "live". The api should see this and should get the connectionstring that corresponds with the name "live". This last part is something I am trying, but nothing works.
This I tried:
Adding session to webapi. This means I break the stateless idea of REST api: not done
Statics cannot work either, because everyone could get the same connectionstring, but its user specific
Google, but most of the examples don't work for me
Searching StackOverflow... See previous point.
This is driving me crazy! There should be a way to change the connectionstring given by a value in a request header, right?
I have the same scenario in a multi-tenant application I created where I use a different connection string for each tenant.
It doesn't matter the implementation you choose, but you have to determine how you are going to differentiate each request per connection string. In my application, I created a custom route value, and used it in the url to differentiate each request. The important thing is to create whatever this mechanism is, and it needs to be the 1st thing you register in your DI framework, on a per request basis.
For example (using Ninject):
private static void RegisterServicdes(IKernel kernel)
{
kernel.Bind<ISiteContext>().To<SiteContext>().InRequestScope();
kernel.Bind<IDbContextFactory>().To<DbContextFactory>().InRequestScope();
// register other services...
}
Rather than your implementation of your DbContext, I would change to be this, then always create your DbContext instance via a DbContextFactory.
public class IocDbContext : DbContext, IDbContext
{
public IocDbContext(string connectionStringType) : base(connectionStringType) { }
}
Then you need to create a DbContextFactory that you use when you create your DbContext, and take the above class as a dependency. Or you can take the dependency into your services, and pass it into the DbContextFactory instead.
public interface IDbContextFactory
{
TestModel CreateContext();
}
public class DbContextFactory : IDbContextFactory
{
private string _siteType;
public DbContextFactory(ISiteContext siteContext)
{
_siteType = siteContext.Tenant;
}
public TestModel CreateContext()
{
return new TestModel(FormatConnectionStringBySiteType(_siteType));
}
// or you can use this if you pass the IMultiTenantHelper dependency into your service
public static TestModel CreateContext(string siteName)
{
return new TestModel(FormatConnectionStringBySiteType(siteName));
}
private static string FormatConnectionStringBySiteType(string siteType)
{
// format from web.config
string newConnectionString = #"data source={0};initial catalog={1};integrated security=True;MultipleActiveResultSets=True;App=EntityFramework";
if (siteType.Equals("a"))
{
return String.Format(newConnectionString, #"(LocalDb)\MSSQLLocalDB", "DbOne");
}
else
{
return String.Format(newConnectionString, #"(LocalDb)\MSSQLLocalDB", "DbTwo");
}
}
}
Then you can use it like so when accessing your DbContext:
public class DbAccess
{
private IDbContextFactory _dbContextFactory;
public DbAccess(IDbContextFactory dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public void DoWork()
{
using (IocDbContext db = _dbContextFactory.CreateContext())
{
// use EF here...
}
}
}
ISiteContext interface implementation (for using route).
public interface ISiteContext
{
string Tenant { get; }
}
public class SiteContext : ISiteContext
{
private const string _routeId = "tenantId";
private string _tenant;
public string Tenant { get { return _tenant; } }
public SiteContext()
{
_tenant = GetTenantViaRoute();
}
private string GetTenantViaRoute()
{
var routedata = HttpContext.Current.Request.RequestContext.RouteData;
// Default Routing
if (routedata.Values[_routeId] != null)
{
return routedata.Values[_routeId].ToString().ToLower();
}
// Attribute Routing
if (routedata.Values.ContainsKey("MS_SubRoutes"))
{
var msSubRoutes = routedata.Values["MS_SubRoutes"] as IEnumerable<IHttpRouteData>;
if (msSubRoutes != null && msSubRoutes.Any())
{
var subRoute = msSubRoutes.FirstOrDefault();
if (subRoute != null && subRoute.Values.ContainsKey(_routeId))
{
return (string)subRoute.Values
.Where(x => x.Key.Equals(_routeId))
.Select(x => x.Value)
.Single();
}
}
}
return string.Empty;
}
}
API action:
[Route("api/{tenantId}/Values/Get")]
[HttpGet]
public IEnumerable<string> Get()
{
_testService.DoDatabaseWork();
return new string[] { "value1", "value2" };
}
you need to create a factory class for Dynamic picking of connection string.
It is the responsibility of that class to give correct connectionString based on the certain Parameter.
Summary: Im working with C# 4.5 version and more specifically in Web API.
Im trying to build an object and wrap it with attributes so when I receive a HTTP POST request, validation will be made in modelState.
a little example before code:
Lets say I have this following request object
public class PlayerRequest
{
[TeamId]
public string TeamId {set;get;}
[UserId]
public string UserId {set;get;}
}
now, I want to be able to just add an attribute to the class and it will check if class contains TeamId and UserId and if so, validate in db that in fact user has access to team.
so lets say, the declaration will be something like:
[PairsValidate]
public class TeamRequest
{
//...
}
What I aim to create is not a specific validation for TeamId and UserId but to create some sort of a pool of attribute pairs and run a simple loop to detect them and validate.
code so far:
[AttributeUsage(AttributeTargets.Class)]
public sealed class AccessValidator : ValidationAttribute
{
private readonly AttributePairValidator[] _validators =
{
UserIdTeamIdValidator.GetInstance(AccessManager.UserAccessToTeam)
};
public override bool IsValid(object value)
{
PropertyInfo[] properties = value.GetType().GetProperties();
foreach (PropertyInfo p in properties)
{
foreach (AttributePairValidator valPair in _validators)
{
valPair.Accept(/* here is the problem */ , p.GetValue as string);
}
}
}
}
public class AttributePairValidator
{
protected string fieldA;
protected string fieldB;
protected Func<string, string, Task<bool>> _validationMethod;
protected static object _lockObj = new object();
protected AttributePairValidator(Func<string, string, Task<bool>> validationMethod)
{
_validationMethod = validationMethod;
}
public bool Accept (ValidationAttribute attr, string val)
{
return true;
}
protected async Task<bool> Check()
{
if (!String.IsNullOrEmpty(fieldA) && !String.IsNullOrEmpty(fieldB))
return await _validationMethod(fieldA, fieldB);
return true;
}
}
public sealed class UserIdTeamIdValidator : AttributePairValidator
{
private static UserIdTeamIdValidator _instance = null;
private UserIdTeamIdValidator(Func<string, string, Task<bool>> validationMethod) : base (validationMethod)
{
}
public static UserIdTeamIdValidator GetInstance(Func<string, string, Task<bool>> validationMethod)
{
lock (_lockObj)
{
if (_instance == null)
_instance = new UserIdTeamIdValidator(validationMethod);
}
return _instance;
}
public async Task<bool> Accept(UserIdAttribute attr, string val)
{
fieldA = val;
return await Check();
}
public async Task<bool> Accept(TeamIdAttribute attr, string val)
{
fieldB = val;
return await Check();
}
}
other issue, if you guys already know how to solve it.
Im validating the request itself by headers and im storing some data in the actionContext's principal. In controllers i use: ActionContext.RequestContext.Principal.Identity.Name
is there any way to get this data when in validationAttribute scope?
Thanks.
So we have a class that does needs to output the result of an operation. Now this was tightly-coupled to emails, however with dependency injection I thought I could add more persistence options, eg. save to disk.
The problem is that saving to disk requires a path, while 'saving' as an email requires other details (from, to, etc).
Is this something that can be achieved through dependency injection? Or am I doing the whole thing wrong? Check code below and my comments to better understand my problem...
public class OriginalClass
{
IPersistence _persistence;
public OriginalClass(IPersistence persistence)
{
this._persistence = persistence;
}
public void DoSomething()
{
// I have all the information needed to send an email / save to disk. But how do I supply it?
this._persistence.Put("Message to save");
}
}
public interface IPersistence
{
bool Put<T>(T data);
}
public class EmailPersistence : IPersistence
{
public bool Put<T>(T data)
{
// How am I going to get the FROM and TO details?
return EmailManager.Send("FROM", "TO", data.ToString());
};
}
public class DiskPersistence : IPersistence
{
public bool Put<T>(T data)
{
// How am I going to get the SAVE PATH details?
// I just used a new initialization. So I'm probably doing this wrong as well...
new System.IO.StreamWriter("SAVE PATH").Write(data.ToString());
return true;
}
}
What you need to do is pass 'just enough' contextual information about the message to the persistence class. Passing on email-specific information like from and to however, causes you to leak implementation details of the persistence mechanism into OriginalClass, which is not something you should want. Doing this will cause you to have to change the OriginalClass everytime you add a new IPersistence implementation. This is obviously bad (it breaks both OCP and DIP).
So what exactly to supply is something only you can determine, but it could be something identifier that allows an implementation to retrieve the required information to operate. This could be something like the ID of the Contactperson or organization for who the message is written. This way you only have to pass in the message and this ID and the implementation can use this ID to query the database to get whatever it needs.
However, if these values do not change during the application's runtime, the solution is completely different. In that case you should simply use constructor injection:
public class EmailPersistence : IPersistence {
private readonly MailAddress from;
private readonly MailAddress to;
public EmailPersistence(MailAddress from, MailAddress to) {
this.from = from;
this.to = to;
}
public bool Put(string data) {
// How am I going to get the FROM and TO details?
return EmailManager.Send(this.from, this.to, data.ToString());
};
}
Since the settings do not change, you can load them from the config file (or from anywhere) during application startup and can simply create a new EmailPersistence using these fixed configuration values.
Something like this should work, As now IEmailManager can also go via the DI framework, all you need to do is to bootstrap the EmailManager Construction.
public class OriginalClass
{
IPersistence _persistence;
public OriginalClass(IPersistence persistence)
{
this._persistence = persistence;
}
public void DoSomething()
{
// I have all the information needed to send an email / save to disk. But how do I supply it?
this._persistence.Put("Message to save");
}
}
public interface IPersistence
{
bool Put<T>(T data);
}
public class EmailPersistence : IPersistence
{
private readonly IEmailManager _manager;
public EmailPersistence(IEmailManager manager)
{
_manager = manager;
}
public bool Put<T>(T data)
{
// How am I going to get the FROM and TO details?
return _manager.Send();
}
}
public class EmailManager : IEmailManager
{
public string From { get; set; }
public string To { get; set; }
public bool Send()
{
throw new NotImplementedException();
}
public dynamic Data { get; set; }
}
public interface IEmailManager
{
string From { get; set; }
string To { get; set; }
dynamic Data { get; set; }
bool Send();
}
public class DiskPersistence : IPersistence
{
public string Path { get; set; }
public DiskPersistence(string path)
{
Path = path;
}
public bool Put<T>(T data)
{
// How am I going to get the SAVE PATH details?
// I just used a new initialization. So I'm probably doing this wrong as well...
new System.IO.StreamWriter(Path).Write(data.ToString());
return true;
}
}
I am working with insurance and have two different policy types - motor and household, represented by two different classes, Motor and Household.
Both have several bits of data in common, so both would inherit from another class called Policy. When a user logs into the app, they could have either a motor or a household policy, so the app needs to display the generic information and the information unique to Motor or Household. To encapsulate all this, i have a response object that has both a Motor member and a Household member, as shown below:
public class Response
{
...
private MotorPolicy _motorPolicy;
private HouseholdPolicy _householdPolicy;
....
}
The code below should demonstrate:
if (response.PolicyType == Enumerations.PolicyType.Motor)
{
lblDescription.Text = response.MotorPolicy.Description;
lblReg.Text = response.MotorPolicy.Reg;
}
else
{
lblDescription.Text = response.HouseholdPolicy.Description;
lblContents.Text = response.HouseholdPolicy.Contents;
}
The MotorPolicy doesn't have Contents property and the HouseholdPolicy doesn't have a Reg property.
But I really want to simply do:
if (response.PolicyType == Enumerations.PolicyType.Motor)
{
lblDescription.Text = response.Policy.Description;
...
}
I have tried using generics, could couldn't find the right solution.
Your response only needs a Policy type, you can then store a MotorPolicy or HouseholdPolicy type into it.
Then your response just needs to check for data type
if (response.Policy is MotorPolicy) ....
Alternatively have an abstract method or a property returning data from an abstract method on the Policy type that is fully inplemented by the child classes and returns reg data or contents data as apporpriate.
Each Policy descendant (now you have two, you might have more in the future, right?) should have their own UI controls which "know" how to deal with the policy information. The same approach can be used for other things, such as a "controller" for policy objects etc.
The response can then be made generic:
public class Response<T> where T: Policy {
...
private T _policy;
....
}
Alternatively, you could have a more generic approach which uses reflection to display the information, but those are usually less "sexy" in their appearance and usability (think of the Property Grid in the VS designer).
public interface IPolicy
{
string Description { get; }
string Reg { get; }
string Contents { get; }
}
public class MotorPolicy : IPolicy
{
public string Description
{
get { return ...; }
}
public string Reg
{
get { return ...; }
}
public string Contents
{
get { return String.Empty; }
}
}
public class HousholdPolicy : IPolicy
{
public string Description
{
get { return ...; }
}
public string Reg
{
get { return String.Empty; }
}
public string Contents
{
get { return ...; }
}
}
public class Response
{
...
private IPolicy _policy;
....
}
Now you don't need an Enumeration to show which type you've implemented, you can just say
lblDescription.Text = response.Policy.Description;
lblReg.Text = response.Policy.Reg;
lblContents.Text = response.Policy.Contents;
Edit: Alternate solution
public interface IPolicy
{
string Description { get; }
}
public interface IHasReg
{
string Reg { get; }
}
public interface IHasContents
{
string Contents { get; }
}
public class MotorPolicy : IPolicy, IHasReg
{
public string Description
{
get { return ...; }
}
public string Reg
{
get { return ...; }
}
}
public class HouseholdPolicy : IPolicy, IHasContents
{
public string Description
{
get { return ...; }
}
public string Contents
{
get { return ...; }
}
}
public class Response
{
...
private IPolicy _policy;
....
}
This leaves you with more code in the calling function
lblDescription.Text = response.Policy.Description;
IHasReg hasReg = response.Policy as IHasReg;
if (hasReg != null) lblReg.Text = hasReg.Reg;
IHasContents hasContents = response.Policy as IHasContents;
if (hasContents != null) lblContents.Text = hasContents.Contents;
but is considerably more extensible than other options presented and complies with your desire to avoid functionality in the implementation which doesn't make sense.
One option is to add a member to Policy that synthesizes all the derived class' relevant properties to provide a summary:
public abstract class Policy {
public string Description { get; set; }
public abstract string Summary { get; }
}
public class MotorPolicy: Policy {
public override string Summary {
get { return this.Description + "\r\n" + this.Reg; }
}
}
public class HouseholdPolicy: Policy {
public override string Summary {
get { return this.Description + "\r\n" + this.Contents; }
}
}
This centralizes the logic and makes the user interface code simple:
label.Description.Text = response.Policy.Summary;
That basic implementation sacrifices the ability to format the subsections separately. You could overcome that by exposing the summary as a collection of strings:
public abstract IEnumerable<string> SummarySections { get; }
If you want to display the derived classes' details in fundamentally different ways, you'll have to embrace the conditional logic in the user interface layer (for example, you might list the household policy's contents in a table, but show a scanned image for the motor policy's registration).
Use the template pattern:
Create a base class called Policy with a virtual abstract get method to determine the description of the policy.
public abstract class Policy
{
protected virtual string GetDescription()
{
return string.Empty()
}
public string Description
{
get
{
return GetDescription();
}
}
}
public MotorPolicy : Policy
{
public override string GetDescription()
{
return ..... ////specific description implementation for MotorPolicy
}
}
public HouseHoldPolicy : Policy
{
public override string GetDescription()
{
return ..... ////specific description implementation for HouseholdPolicy
}
}
public class Response
{
...
private MotorPolicy _motorPolicy;
private HouseholdPolicy _householdPolicy;
private PolicyType _policyType;
....
public Policy Policy
{
get
{
if (_policyType== PolicyType.Motor)
{
return _motorPolicy;
}
if (_policyType== PolicyType.Household)
{
return _householdPolicy;
}
return null;
}
}
}
client code:
if (response.Policy != null)
{
lblDescription.Text = response.Policy.Description;
...
}
Let MotorPolicy and HouseholdPolicy derive from Policy and override the abstract get method from the base and create a specific implementation of it.
In the Response class just get the description.
The simplest solution would be to implement an interface with a description property and a "contents" property, and then in your motor policy class, create a dummy "contents" property which returns "reg".
Can your response contain either a MotorPolicy or a HouseholdPolicy or, can it contain one of each?
If you are dealing with one or the other then create a base type that both classes inherit that defines the common properties. When you output the common properties just cast the Policy as the base type and use that.
My immediate thought is to go for:
public abstract class Response
{
public abstract Policy Policy {get;}//can be used for stuff for dealing with all policies.
public static Response GetResponse(Policy policy)
{//factory method
if(policy is MotorPolicy)
return new MotorResponse((MotorPolicy)policy);
if(policy is HouseholdPolicy)
return new HouseholdResponse((HouseholdPolicy)policy);
throw new ArgumentException("Unexpected policy type");
}
}
public class MotorResponse : Response
{
private readonly MotorPolicy _motorPolicy;
public MotorResponse(MotorPolicy policy)
{
_motorPolicy = policy;
}
protected override Policy Policy
{
get { return _motorPolicy; }
}
// motor specific stuff
}
public class HouseholdResponse : Response
{
private readonly HouseholdPolicy _householdPolicy;
public HouseholdResponse(HouseholdPolicy policy)
{
_householdPolicy = policy;
}
protected override Policy Policy
{
get { return _householdPolicy; }
}
// household specific stuff
}
I would try something like this:
public class Response
{
public Policy SelectedPolicy {get;set;}
//I don't think you need these, but hard to
//say without seeing the rest of the code
...
private MotorPolicy _motorPolicy;
private HouseholdPolicy _householdPolicy;
....
}
then
lblDescription.Text = response.SelectedPolicy.Description;
if (SelectedPolicy is MotorPolicy)
lblReg.Text = ((MotorPolicy)response.SelectedPolicy).Reg;
else if (SelectedPolicy is HouseholdPolicy)
lblContents.Text = ((HouseholdPolicy)response.SelectedPolicy).Contents;
I would not put both Reg and Contents in the base class or interface. If I do what's the purpose of inheritance if all classes look the same? The only benefits I would get would be types, and that's not going to gain me much in this case.
maybe I don't understand the question but I would just use inheritence
define policy as
public class Policy
{
public string Description{ get; set;}
public string Details {get; set;}
}
public class MotorPolicy:Policy
{
public void SetReg(string reg)
{
base.Details = reg;
}
}
public class HousePolicy:Policy
{
public void SetContents(string contents)
{
base.Details = contents;
}
}
and call by
private void Form1_Load(object sender, EventArgs e)
{
MotorPolicy mp = new MotorPolicy();
mp.Description = "Motor";
SetForm(mp);
}
private void SetForm(Policy p)
{
lblDescription.Text = p.Description;
lblDetail.Text = p.Details;
//then if you still need specifics
if (p.GetType() == typeof(MotorPolicy))
{
MotorPolicy mp = p as MotorPolicy;
//continue assigning mp
}
else if (p.GetType() == typeof(HousePolicy))
{
HousePolicy hp = p as HousePolicy;
//continue assigning Hp
}
}
Note I put reg/contents as a field detail as they are both string types. If one was int vs string then they would have to be done separate.
define the Policy interface and implement it in your both the policy classes
Interface IPolicy{
int Reg {get;set;};
string Contents {get;set;};
}
MotorPolicy : Policy,IPolicy {
string IPolicy.Contents
{get;set;};
int IPolicy.Reg
{get;set;};
}
HouseholdPolicy : Policy , IPolicy {
string IPolicy.Contents
{get;set;};
int IPolicy.Reg
{get;set;};
}
Yours is a unique example of "Refactoring condition to Polymorphism" [Fowler].
And then your method should accept the proper object and do as below:
public void Update(IPolicy policy)
{
lblDescription.Text = policy.Description;
lblReg.Text = .Reg;
}
Well, I dislike abstract classes so I went with an interface for Policy
public interface IPolicy
{
string Description { get; set;}
void Display();
}
Then we inherit from it to create MotorPolicy
public class MotorPolicy : IPolicy
{
public string Description { get; set; }
public string Reg { get; set; }
public void Display()
{
Console.WriteLine(string.Format("Description: {0}", Description));
Console.WriteLine(string.Format("Reg: {0}", Reg));
}
}
Then for response I changed the Policy to a List in the off chance that you can have both or either. Now we've offloaded the handling of displaying the data to the specific policy itself.
public class Response
{
public List<IPolicy> Policies { get; set; }
public void Display()
{
Policies.ForEach(p => p.Display());
}
public void Display(Type t)
{
var policy = (from p in Policies
where p.GetType() == t
select p).FirstOrDefault();
policy.Display();
}
}
This could easily be changed to not use the List and we can get rid of the overloaded Display.