Is there any way to inject a parameter to constructor, which that parameter is currently created in Initialize method on basecontroller?
sample code:
public class SSBaseController : Controller
{
protected UserProfileClass UserProfile;
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
UserProfile = UserProfileGetter.getProfileFromDB();
}
}
public class SSController:SSBaseController
{
private IProcessService processService;
public SSController(IProcessService _processService)
{
processService = _processService;
}
}
public interface IProcessService
{
void doStuff();
}
public class ProcessService1 : IProcessService
{
private UserProfileClass upc;
private string _name;
public ProcessService1(UserProfileClass _profileClass)
{
upc = _profileClass;
}
public void doStuff()
{
_name = upc.name;
upc.name = "xxx";
}
}
public class UserProfileGetter
{
public static UserProfileClass getProfileFromDB()
{
return null;
}
}
public class UserProfileClass
{
public string name;
}
Also i want to get rid of initialize, is this possible?
how to register ProcessService with that parameter without being null in SSController?
It is possible to integrate ASP.NET MVC and Autofaq. The only two things you have to do then is to register interface implementation and specify the Controller's constructor params. Framework will do all the rest.
See https://code.google.com/p/autofac/wiki/MvcIntegration
Here is one more article: http://blogs.msdn.com/b/roncain/archive/2012/07/16/dependency-injection-with-asp-net-web-api-and-autofac.aspx
Related
I have an existing C# console application that takes arguments and based on the arguments
creates an instance of markets (UK, US, MX..) using dependency injection.
Each market class does a 'string GetData()', 'string ProcessData()' and 'bool ExportData()'.
The application was initially created for one eCommerce vendor's markets. Now I am told to modify it for a different vendor that does a different process. The high-level flow remains the same.
'GetData' to fetch records from DB,
'ProcessData' for any transformation or the likes
'ExportData'.
The difference is Getdata() pulls records from DB and maps to an object. I am planning to use Petapoco. 'ProcessData' might return a similar class. 'Exportdata' currently does an API call but for the new vendor, I have to write to a file.
I was reading up on patterns I am totally confused. At first, I thought I needed abstract factory pattern and now I think the factory method is what I should be using but I am not sure if I am doing it right. Need some guidance/review here. A sample cs file I created from my understanding of factory pattern. This code is based on the headfirst code samples.
using System;
using System.Collections.Generic;
using StatusExport.Models;
namespace factorymethod
{
class Program
{
static void Main(string[] args)
{
ClientFactory factory = null;
Console.WriteLine("Enter client code:");
string clientCode= Console.ReadLine();
switch (clientCode.ToLower())
{
case "costco":
factory = new CostcoFactory("accountname", "taskname");
break;
//NEw vendor might be added
//case "walmart"
//factory = new WalmartFactory("taskname", "type");
//break
default:
break;
}
bool status = factory.ProcessData();
Console.ReadKey();
}
}
abstract class Client
{
public abstract string AccountName { get; }
public abstract string Task { get; set; }
//More properties might be added. Some may not even be used by some of the new vendors. For example, Costco Might need accountname and task. Tomorrow if walmart comes, they might not need these two or may need task and a new property 'type'
public abstract List<T> GetData<T>();
public abstract List<T> ProcessData<T>();
public abstract bool ExportData();
}
class CostcoClient : Client
{
public override string AccountName { get; }
public override string Task { get; set; }
public CostcoClient(string accountName, string task)
{
AccountName = accountName;
Task = task;
}
public override List<DBRecord> GetData<DBRecord>() //DBRecord class is specific to Costco.
{
List<DBRecord> dbresult = new List<DBRecord>();
//dbresult = db return data mapped to an object DBRecord using petapoco. Another vendor might have a different class to which DB records are mapped. So the return type can be generic
return asn;
}
public override List<T> ProcessData<T>()
{
throw new NotImplementedException(); //Any data transformation or business logic. Return type might be DBRecord or a new class altogether
}
public override bool ExportData()
{
throw new NotImplementedException();//Call API or write data to file and if success send true else false
}
}
abstract class ClientFactory
{
public abstract bool ProcessData();
}
class CostcoFactory : ClientFactory
{
public string AccountName { get; }
public string Task { get; set; }
public CostcoFactory(string accountname, string task)
{
AccountName = accountname;
Task = task;
}
public override bool ProcessData()
{
CostcoClient gc = new CostcoClient(AccountName, Task);
var result = gc.GetData<DBRecord>();
return true;
}
}
}
Do you think this is the right design approach?
I also want to keep the console project independent of vendor project. So maybe 'StatusExport.Program' for the console application. DLL projects StatusExport.Common to hold the interface and abstract classes' and 'StatusExport.Client(ex:StatusExport.Costco)' for each vendor stuff.
You can create BaseClient class that will contains a basic group of properties, and if you need to add something new - just inherit it. You did right, but i think it's better to change public modifier to protected in your properties AccountName and Task, to give access to them only from child classes.
Actually, you can create a BaseClientModels (request/response) for each method if you are not sure that returning type List will be always actual.
Example:
public abstract class BaseClient
{
#region Properties : Protected
protected abstract string AccountName { get; }
protected abstract string Task { get; set; }
#endregion
#region Methods : Public
public abstract BaseGetDataResponseModel GetData(BaseGetDataRequestModel model);
public abstract BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model);
public abstract BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model);
#endregion
}
public class BaseGetDataResponseModel { }
public class BaseGetDataRequestModel { }
public class BaseProcessDataResponseModel { }
public class BaseProcessDataRequestModel { }
public class BaseExportDataResponseModel { }
public class BaseExportDataRequestModel { }
Then let's look on your class CostcoClient and how it can looks like:
public class CostcoClient : BaseClient
{
#region Properties : Protected
protected override string AccountName { get; }
protected override string Task { get; set; }
protected virtual IDataReader<BaseGetDataRequestModel, BaseGetDataResponseModel> DataReader { get; }
protected virtual IDataProcessor<CostcoClientProcessDataRequestModel, CostcoClientProcessDataResponseModel> DataProcessor { get; }
protected virtual IExportDataHandler<CostcoClientExportDataRequestModel, CostcoClientExportDataResponseModel> ExportDataHandler { get; }
#endregion
#region Constructors
public CostcoClient(string accountName, string task)
{
//set DataReader, DataProcessor, ExportDataHandler
AccountName = accountName;
Task = task;
}
#endregion
#region Methods : Public
public override BaseGetDataResponseModel GetData(BaseGetDataRequestModel model)
{
if (model is CostcoClientGetDataRequestModel clientGetDataRequestModel)
{
return DataReader.ReadData(clientGetDataRequestModel);
}
return null; //wrong type has passed
}
public override BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model)
{
if (model is CostcoClientProcessDataRequestModel clientProcessDataRequestModel)
{
return DataProcessor.ProcessData(clientProcessDataRequestModel);
}
return null;
}
public override BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model)
{
if (model is CostcoClientExportDataRequestModel clientExportDataRequestModel)
{
return ExportDataHandler.Handle(clientExportDataRequestModel);
}
return null;
}
#endregion
}
public class CostcoClientGetDataRequestModel : BaseGetDataRequestModel { }
public class CostcoClientGetDataResponseModel : BaseGetDataResponseModel { }
public class CostcoClientProcessDataRequestModel : BaseProcessDataRequestModel { }
public class CostcoClientProcessDataResponseModel : BaseProcessDataResponseModel { }
public class CostcoClientExportDataRequestModel : BaseExportDataRequestModel { }
public class CostcoClientExportDataResponseModel : BaseExportDataResponseModel { }
public interface IDataReader<TIn, TOut>
{
public TOut ReadData(TIn model);
}
public interface IDataProcessor<TIn, TOut>
{
public TOut ProcessData(TIn model);
}
public interface IExportDataHandler<TIn, TOut>
{
public TOut Handle(TIn model);
}
public class CostcoClientDataReader : IDataReader<CostcoClientGetDataRequestModel, CostcoClientGetDataResponseModel>
{
public CostcoClientGetDataResponseModel ReadData(CostcoClientGetDataRequestModel model)
{
throw new NotImplementedException();
}
}
//and so on
You have to implement IDataReader, IDataProcessor, IExportDataHandler, make your logic and call it from GetData, ProcessData, ExportData methods, as an example, and get instances via dependency injection.
Then, we can change your factory to this:
public interface IClientFactory
{
BaseClient GetClientService(ClientServicesEnum value);
}
public class BaseClientFactory : IClientFactory
{
#region Propertied : Protected
protected virtual IEnumerable<BaseClient> Services { get; }
protected string AccountName { get; }
protected string Task { get; set; }
#endregion
#region Constructors
public BaseClientFactory(IEnumerable<BaseClient> services, string accountname, string task)
{
Services = services;
AccountName = accountname;
Task = task;
}
#endregion
public BaseClient GetClientService(ClientServicesEnum value)
=> Services.First(x => x.GetType().Equals(GetClientServiceByCode()[value]));
private Dictionary<ClientServicesEnum, Type> GetClientServiceByCode()
=> new Dictionary<ClientServicesEnum, Type>()
{
{ ClientServicesEnum.CostcoClient, typeof(CostcoClient) }
};
}
public enum ClientServicesEnum
{
CostcoClient = 1,
Another2 = 2,
Another3 = 3
}
Where
protected virtual IEnumerable<BaseClient> Services { get; }
you can get via DI too, and then get correct ServiceHandler by enum.
And your main function to call all this:
switch (clientCode)
{
case 1:
baseClient = ClientFactory.GetClientService(ClientServicesEnum.CostcoClient);
break;
case 2:
baseClient = ClientFactory.GetClientService(ClientServicesEnum.Another2);
break;
default:
break;
}
bool status = baseClient.ProcessData(null); //your model
The main thing is - you can use more than one pattern, for example one from Creational patterns, and one from Structural.
If i need some help in code architecture i use this:
https://refactoring.guru/
I think, using this example you can remove properties AccountName and Task, because of request models in methods.
I have an interface as below, which I use to add a specific language if it does not exist:
public interface IGetLanguagesService
{
void GetLanguages(ILocalizationService localization);
}
public class LanguageService : IGetLanguagesService
{
ILocalizationService _localizationService;
public void GetLanguages(ILocalizationService localization)
{
_localizationService = localization;
var currentLanguages = _localizationService.GetAllLanguages();
bool exists = false;
foreach (var currentLan in currentLanguages)
{
if (currentLan.IsoCode == "es-ES")
{
exists = true;
}
}
if (!exists)
{
AddLanguage(_localizationService);
}
}
public void AddLanguage(ILocalizationService localization)
{
var languageSE = new Language("es-ES") { CultureName = "es-ES", IsMandatory = true };
localization.Save(languageSE);
}
}
I want to use this at start-up so have created a component composer, which on Initialize() I want to call CallGetLanguages() but Im not entirely sure what should be in Initialize(), I think my DI may be wrong?
public class LanguagesComposer : ComponentComposer<LanguagesComponent>
{
public void Compose(Composition composition)
{
composition.Register<IGetLanguagesService>(Lifetime.Singleton);
composition.Register<ILocalizationService>(Lifetime.Singleton);
composition.Components().Append<LanguagesComponent>();
}
}
public class LanguagesComponent : IComponent
{
public void Initialize()
{
???????
}
public void Terminate()
{
throw new NotImplementedException();
}
IGetLanguagesService _getLanguagesService;
ILocalizationService _localization;
public void CallGetLanguages(IGetLanguagesService getLanguages, ILocalizationService localization)
{
_getLanguagesService = getLanguages;
_localization = localization;
_getLanguagesService.GetLanguages(localization);
}
}
You've passed ILocalizationService localization instance to LanguageService twice, pass it to constructor instead and use a constructor injection. The same issue with LanguagesComponent, pass all its dependencies to constructor instead of methods
I have replaced the AuditingStore with my own so that I can set the CustomData field, and this is working great.
public class MyAuditingStore : AuditingStore
{
public MyAuditingStore(IRepository<AuditLog, long> auditLogRepository)
: base(auditLogRepository)
{
}
public override Task SaveAsync(AuditInfo auditInfo)
{
auditInfo.CustomData = "certain additional data that is not captured by default";
return base.SaveAsync(auditInfo);
}
}
But now I want to know how to inject services into the AuditingStore so that I can retrieve other information during SaveAsync. How is this done?
Similar to how you would inject services elsewhere.
public class MyAuditingStore : AuditingStore
{
private readonly OtherInformationService _otherInformationService;
public MyAuditingStore(
IRepository<AuditLog, long> auditLogRepository,
OtherInformationService otherInformationService)
: base(auditLogRepository)
{
_otherInformationService = otherInformationService;
}
public override Task SaveAsync(AuditInfo auditInfo)
{
auditInfo.CustomData = otherInformationService.GetOtherInformation();
return base.SaveAsync(auditInfo);
}
}
public class OtherInformationService : ITransientDependency
{
public string GetOtherInformation()
{
return "other information";
}
}
I am trying to pass a parameter to a child ViewModel constructor which throws "MvvmCross.Platform.Exceptions.MvxException: Failed to construct and initialize ViewModel ... MvxIoCResolveException: Failed to resolve parameter for parameter myParam of type MyType..."
MyChildViewModel.cs
public class MyChildViewModel : MvxViewModel
{
private MyType _myParam;
public MyType MyParam
{
get { return _myParam; }
set
{
if (SetProperty(ref _myParam, value))
{
RaisePropertyChanged(() => MyParam);
}
}
}
public MyChildViewModel(MyType myParam)
{
_myParam = myParam;
}
}
In my parent ViewModel I have:
public ICommand ShowDialogCommand { get; private set; }
ShowDialogCommand = new MvxCommand<MyType>(e => ShowViewModel<MyChildViewModel>(e));
Parent activity call:
ViewModel.ShowDialogCommand.Execute(VarOfMyType);
I am obviously doing something wrong. Is this even remotely acceptable approach to pass data to a child ViewModel? What's the best practice?
Thank you in advance for your valuable time.
If you read up on the documentation
it is easy to pass object with the MvxNavigationService: https://www.mvvmcross.com/documentation/fundamentals/navigation
Note that the documentation is for MvvmCross 5.2 which is currently in a nightly release, but almost the same works for 5.0 and onwards.
In your ViewModel this could look like:
public class MyViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
public MyViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
}
public override void Prepare()
{
//Do anything before navigating to the view
}
public async Task SomeMethod()
{
await _navigationService.Navigate<NextViewModel, MyObject>(new MyObject());
}
}
public class NextViewModel : MvxViewModel<MyObject>
{
public override void Prepare(MyObject parameter)
{
//Do anything before navigating to the view
//Save the parameter to a property if you want to use it later
}
public override async Task Initialize()
{
//Do heavy work and data loading here
}
}
From this website the way they did it is (adapted and modified for your case):
public ICommand ShowDialogCommand { get; private set; }
ShowDialogCommand = new MvxCommand<MyType>(ShowMyVM);
private void ShowMyVM(MyType e)
{
if (e != null)
ShowViewModel<SingleClientViewModel>(e);
else
{
//handle case where your parameter is null
}
}
I have a base class called Message like this:
public abstract class Message
{
protected int m_id;
protected bool m_localized;
protected string m_metaData;
public int GetID() { return m_id; }
public bool GetLocalized() { return m_localized; }
public string GetMetadata() { return m_metaData; }
}
Then, i have two more classes that inherit from Message for example:
public class ClassicMessage : Message
{
private string m_title;
private string m_content;
public void SetTitle(string title) { m_title = title; }
public void SetContent(string content) { m_content = content; }
public string GetTitle() { return m_title; }
public string GetContent() { return m_content; }
}
public class MessageWithCustomContent : Message
{
private List<CustomContent> m_content;
public MessageWithCustomContent()
{
m_content = new List<CustomContent>();
}
public List<CustomContent> GetContent()
{
return m_content;
}
public CustomContent GetContentEntry(int id)
{
return m_content.find(x => x.ID.Equals(id));
}
}
public class CustomContent
{
private int m_id;
public int ID { get; set { m_id = value; } }
private string m_body;
public string Body { get { return m_body; } set { m_body = value; }
private Image m_image;
public Image Image { get { return m_image; } set { m_image = value; } }
}
In a case like this, how can i unify the app interface if the derived classes has similar methods but these methods have different return types? (even when the methods try to do the same)
I know that with the example i'm breaking the Liskov Substitution Principle and the Open/Closed principle, what's the best approach to get around with that?
Thanks for your help!
Edit:
For more clarity, what i'm trying to achieve is to create a common interface to manage all the possible messages as the base "Message", because i want to avoid using typeof in the consumer class.
for example:
if(message is MessageWithCustomContent)
{
// do something with the contents.
}
else if(message is MessageWithCustomContent)
{
// do another thing with the contents.
}
etc...
You could change Message to be generic, and the T would specify the Content return type. See example below.
Edit
You could use a "IMessage" and a "Message: IMessage" as base.
You would then be able to create a IMessage list like so
var messages = new List<IMessage>
{
new ClassicMessage(),
new MessageWithCustomContent()
};
foreach (var message in messages)
{
message.GetContent();
}
Below is how the implementation of IMessagecould be done.
public interface IMessage
{
int GetID();
bool GetLocalized();
string GetMetadata();
object GetContent();
}
public abstract class Message<T> : IMessage
{
protected int m_id;
protected bool m_localized;
protected string m_metaData;
public int GetID() { return m_id; }
public bool GetLocalized() { return m_localized; }
public string GetMetadata() { return m_metaData; }
object IMessage.GetContent()
{
return GetContent();
}
public abstract T GetContent();
}
public class ClassicMessage : Message<string>
{
private string m_title;
private string m_content;
public void SetTitle(string title) { m_title = title; }
public void SetContent(string content) { m_content = content; }
public string GetTitle() { return m_title; }
public override string GetContent()
{
return m_content;
}
}
public class MessageWithCustomContent : Message<List<CustomContent>>
{
private List<CustomContent> m_content;
public MessageWithCustomContent()
{
m_content = new List<CustomContent>();
}
public CustomContent GetCustomContent(int id)
{
return null;
}
public override List<CustomContent> GetContent()
{
return m_content;
}
}
public class CustomContent
{
private int m_id;
public int ID { get; set; }
private string m_body;
public string Body
{
get { return m_body; }
set { m_body = value; }
}
}
I will explain how you break LSP below but before I do that, you are not really doing any inheriting. Yes you are declaring your classes to be inheriting but you are not really inheriting anything. So before learning LSP, perhaps you need to get a grip on inheritance firstly.
How do I know if I am breaking LSP?
Lest say your Message class was like this, notice the virtual and abstract methods:
public abstract class Message
{
protected int m_id;
protected bool m_localized;
protected string m_metaData;
public virtual int GetID() { return m_id; }
public virtual bool GetLocalized() { return m_localized; }
public abstract string GetMetadata();
}
Create a list like this:
var messages = new List<Message>();
Then add concrete types to that list of all the inheriting types. Then do this:
foreach(var thisMessage in messages)
{
var id = thisMessage.GetID();
var loc = GetLocalized();
var meta = GetMetadata();
}
If you get no exception thrown because one of the inheriting classes decided it does not need one of those methods, then you have not broken LSP. The idea is that if something is inheriting Message, then it should inherit everything. Otherwise, we cannot safely and with confidence substitute the inherited one for the parent one.
The reason this principle is important is because there may be existing code which is using Message, as shown in the foreach above, where it is treating all the types polymorphically and a developer decides to inherit it like this:
public abstract class BadMessage
{
public override int GetID()
{
throw new InvalidOperationException
("This method is not needed for BadMessage and should not be called");
}
public override bool GetLocalized() { ... }
public override string GetMetadata() { ... }
}
You see this will break existing code. And the worst part is, the compiler will not even be able to catch it, until it surfaces like an ugly bug in production.
Well, you're missing the interface methods in de base class. Abstract functions, that get implemented in the derivative classes. If you get a Message, not knowing what kind it is, how would you request its contents?
You could add derivative-specific methods to your base, but you'd have to implement an not_implemented exception in a virtual implementation in the base class to compensate for all derivatives not implementing it, and add exception handling. But then you should ask yourself: " is this class really a derivative? What do I want to achieve."