Method parameters design consideration - c#

I have a AddCustomer() that has four parameters (firName, lastName, email, companyId), like below.
public class CustomerService
{
public bool AddCustomer(
string firName, string lastName,
string email, int companyId)
{
//logic: create company object based on companId
//other logic including validation
var customer = //create customer based on argument and company object
//save the customer
}
}
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Company Company { get; set; }
public string EmailAddress { get; set; }
//Other five primitive properties
}
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
}
My Question is that should the AddCustomer's parameter be changed to Customer object, like below, considering SOLID principle. Please note that only four fields shown above are used in the method.
public bool AddCustomer(Customer customer){
}
Update
If below is used:
public bool AddCustomer(Customer customer)
The issue: One of the parameter is CompanyId. Thus, creating a Customer constructor with a CompanyId as parameter might not work on all circumstances. However, without constructor, it would be confusing for AdCustomer()'s client as to what properties to assign.
Update 2
Ideally, i would like to protect invariant of entities Customer and Company by restricting property setters.

An answer very much depends on what the purpose and the responsibility of the CustomerService class and the Customer class is, and what they are intended to achieve.
From your question it would seem ("other logic including validation") that it is the responsibility of CustomerService to determine what constitutes a valid new Customer to be registered, whereas the Customer class itself is nothing more than a DTO without any behavior.
So consider the following hypothetical use cases: a customer's email changes; the Company the Customer works for changes; if the Company is bankrupt, the new Customer registration should be refused; if the Company produces a lot of sales for us, the Customer should be regarded as a Premium Customer. How would such cases be handled and what responsibilities are involved?
You might want to approach this differently, in the sense that you make both intent and behavior explicit, instead of having "AddCustomer", "UpdateCustomer", "DeleteCustomer" and "GetCustomer(Id)". The Customer service could be responsible for service coordination and infrastructure aspects, while the Customer class really focuses on the required domain behavior and customer related business rules.
I will outline one (a CQRS type approach) of several possible approaches to better break up responsibilities, to illustrate this:
Encode behavioral intent and decisions as Commands and Events respectively.
namespace CustomerDomain.Commands
{
public class RegisterNewCustomer : ICommand
{
public RegisterNewCustomer(Guid registrationId, string firstName, string lastName, string email, int worksForCompanyId)
{
this.RegistrationId = registrationId;
this.FirstName = firstName;
// ... more fields
}
public readonly Guid RegistrationId;
public readonly string FirstName;
// ... more fields
}
public class ChangeCustomerEmail : ICommand
{
public ChangeCustomerEmail(int customerId, string newEmail)
// ...
}
public class ChangeCustomerCompany : ICommand
{
public ChangeCustomerCompany(int customerId, int newCompanyId)
// ...
}
// ... more commands
}
namespace CustomerDomain.Events
{
public class NewCustomerWasRegistered : IEvent
{
public NewCustomerWasRegistered(Guid registrationId, int assignedId, bool isPremiumCustomer, string firstName /* ... other fields */)
{
this.RegistrationId = registrationId;
// ...
}
public readonly Guid RegistrationId;
public readonly int AssignedCustomerId;
public readonly bool IsPremiumCustomer;
public readonly string FirstName;
// ...
}
public class CustomerRegistrationWasRefused : IEvent
{
public CustomerRegistrationWasRefused(Guid registrationId, string reason)
// ...
}
public class CustomerEmailWasChanged : IEvent
public class CustomerCompanyWasChanged : IEvent
public class CustomerWasAwardedPremiumStatus : IEvent
public class CustomerPremiumStatusWasRevoked : IEvent
}
This allows expressing intent very clearly, and including only the information that is actually needed to accomplish a specific task.
Use small and dedicated services to deal with the needs of your application domain in making decisions:
namespace CompanyIntelligenceServices
{
public interface ICompanyIntelligenceService
{
CompanyIntelligenceReport GetIntelligenceReport(int companyId);
// ... other relevant methods.
}
public class CompanyIntelligenceReport
{
public readonly string CompanyName;
public readonly double AccumulatedSales;
public readonly double LastQuarterSales;
public readonly bool IsBankrupt;
// etc.
}
}
Have the CustomerService implementation deal with infrastructure / coordination concerns:
public class CustomerDomainService : IDomainService
{
private readonly Func<int> _customerIdGenerator;
private readonly Dictionary<Type, Func<ICommand, IEnumerable<IEvent>>> _commandHandlers;
private readonly Dictionary<int, List<IEvent>> _dataBase;
private readonly IEventChannel _eventsChannel;
private readonly ICompanyIntelligenceService _companyIntelligenceService;
public CustomerDomainService(ICompanyIntelligenceService companyIntelligenceService, IEventChannel eventsChannel)
{
// mock database.
var id = 1;
_customerIdGenerator = () => id++;
_dataBase = new Dictionary<int, List<IEvent>>();
// external services and infrastructure.
_companyIntelligenceService = companyIntelligenceService;
_eventsChannel = eventsChannel;
// command handler wiring.
_commandHandlers = new Dictionary<Type,Func<ICommand,IEnumerable<IEvent>>>();
SetHandlerFor<RegisterNewCustomerCommand>(cmd => HandleCommandFor(-1,
(id, cust) => cust.Register(id, cmd, ReportFor(cmd.WorksForCompanyId))));
SetHandlerFor<ChangeCustomerEmail>(cmd => HandleCommandFor(cmd.CustomerId,
(id, cust) => cust.ChangeEmail(cmd.NewEmail)));
SetHandlerFor<ChangeCustomerCompany>(cmd => HandleCommandFor(cmd.CustomerId,
(id, cust) => cust.ChangeCompany(cmd.NewCompanyId, ReportFor(cmd.NewCompanyId))));
}
public void PerformCommand(ICommand cmd)
{
var commandHandler = _commandHandlers[cmd.GetType()];
var resultingEvents = commandHandler(cmd);
foreach (var evt in resultingEvents)
_eventsChannel.Publish(evt);
}
private IEnumerable<IEvent> HandleCommandFor(int customerId, Func<int, Customer, IEnumerable<IEvent>> handler)
{
if (customerId <= 0)
customerId = _customerIdGenerator();
var events = handler(LoadCustomer(customerId));
SaveCustomer(customerId, events);
return events;
}
private void SetHandlerFor<TCommand>(Func<TCommand, IEnumerable<IEvent>> handler)
{
_commandHandlers[typeof(TCommand)] = cmd => handler((TCommand)cmd);
}
private CompanyIntelligenceReport ReportFor(int companyId)
{
return _companyIntelligenceService.GetIntelligenceReport(companyId);
}
private Customer LoadCustomer(int customerId)
{
var currentHistoricalEvents = new List<IEvent>();
_dataBase.TryGetValue(customerId, out currentHistoricalEvents);
return new Customer(currentHistoricalEvents);
}
private void SaveCustomer(int customerId, IEnumerable<IEvent> newEvents)
{
List<IEvent> currentEventHistory;
if (!_dataBase.TryGetValue(customerId, out currentEventHistory))
_dataBase[customerId] = currentEventHistory = new List<IEvent>();
currentEventHistory.AddRange(newEvents);
}
}
And then that allows you to really focus on the required behavior, business rules and decisions for the Customer class, maintaining only the state needed to perform decisions.
internal class Customer
{
private int _id;
private bool _isRegistered;
private bool _isPremium;
private bool _canOrderProducts;
public Customer(IEnumerable<IEvent> eventHistory)
{
foreach (var evt in eventHistory)
ApplyEvent(evt);
}
public IEnumerable<IEvent> Register(int id, RegisterNewCustomerCommand cmd, CompanyIntelligenceReport report)
{
if (report.IsBankrupt)
yield return ApplyEvent(new CustomerRegistrationWasRefused(cmd.RegistrationId, "Customer's company is bankrupt"));
var isPremium = IsPremiumCompany(report);
yield return ApplyEvent(new NewCustomerWasRegistered(cmd.RegistrationId, id, isPremium, cmd.FirstName, cmd.LastName, cmd.Email, cmd.WorksForCompanyID));
}
public IEnumerable<IEvent> ChangeEmail(string newEmailAddress)
{
EnsureIsRegistered("change email");
yield return ApplyEvent(new CustomerEmailWasChanged(_id, newEmailAddress));
}
public IEnumerable<IEvent> ChangeCompany(int newCompanyId, CompanyIntelligenceReport report)
{
EnsureIsRegistered("change company");
var isPremiumCompany = IsPremiumCompany(report);
if (!_isPremium && isPremiumCompany)
yield return ApplyEvent(new CustomerWasAwardedPremiumStatus(_id));
else
{
if (_isPremium && !isPremiumCompany)
yield return ApplyEvent(new CustomerPremiumStatusRevoked(_id, "Customer changed workplace to a non-premium company"));
if (report.IsBankrupt)
yield return ApplyEvent(new CustomerLostBuyingCapability(_id, "Customer changed workplace to a bankrupt company"));
}
}
// ... handlers for other commands
private bool IsPremiumCompany(CompanyIntelligenceReport report)
{
return !report.IsBankrupt &&
(report.AccumulatedSales > 1000000 || report.LastQuarterSales > 10000);
}
private void EnsureIsRegistered(string forAction)
{
if (_isRegistered)
throw new DomainException(string.Format("Cannot {0} for an unregistered customer", forAction));
}
private IEvent ApplyEvent(IEvent evt)
{
// build up only the status needed to take domain/business decisions.
// instead of if/then/else, event hander wiring could be used.
if (evt is NewCustomerWasRegistered)
{
_isPremium = evt.IsPremiumCustomer;
_isRegistered = true;
_canOrderProducts = true;
}
else if (evt is CustomerRegistrationWasRefused)
_isRegistered = false;
else if (evt is CustomerWasAwardedPremiumStatus)
_isPremium = true;
else if (evt is CustomerPremiumStatusRevoked)
_isPremium = false;
else if (evt is CustomerLostBuyingCapability)
_canOrderProducts = false;
return evt;
}
}
An added benefit is that the Customer class in this case is completely isolated from any infrastructure concerns can be easily tested for correct behavior and the customer domain module can be easily changed or extended to accommodate new requirements without breaking existing clients.

yes.... if its valid to create a customer with those 4 properties.... ideally you'd have a constructor with those 4. that way the create responsibility lives with the customer object and Customer Service doesn't need to know about it, it just deals with "Customers".

How about using the builder pattern resulting in code somewhat like this:
var customer = new CustomerBuilder()
.firstName("John")
.lastName("Doe")
.email("john.doe#example.com")
.companyId(6)
.createCustomer();
customerService.AddCustomer(customer);
Then you can have your builder class handle looking up company objects when createCustomer is called and the order of parameters no longer matters and you have a convenient place to put logic to choose sensible defaults.
This also gives you a convenient location for validation logic so you can't get an invalid instance of Customer in the first place.
Or another possible way would be to have AddCustomer return a command object so your client code could do this:
customerService.AddCustomer()
.firstName("John")
.lastName("Doe")
.email("john.doe#example.com")
.companyId(6)
.execute();

Related

Appropriate design pattern for the payment modules c#

As i am learning through design pattern concept and also wanted to implement the payment modules in my project using the proper design pattern. So for that I have created some sample code.
Currently I have two concrete implementation for the payment PayPal and Credit Card. But the concrete implementation will be added further on the project.
Payment Service
public interface IPaymentService
{
void MakePayment<T>(T type) where T : class;
}
Credit Card and Pay Pal Service
public class CreditCardPayment : IPaymentService
{
public void MakePayment<T>(T type) where T : class
{
var creditCardModel = (CreditCardModel)(object)type;
//Implementation CreditCardPayment
}
}
class PayPalPayment : IPaymentService
{
public void MakePayment<T>(T type) where T : class
{
var payPalModel = (PayPalModel)(object)type;
//Further Implementation will goes here
}
}
Client Code Implementation
var obj = GetPaymentOption(payType);
obj.MakePayment<PayPalModel>(payPalModel);
Get Payment Option
private static IPaymentService GetPaymentOption(PaymentType paymentType)
{
IPaymentService paymentService = null;
switch (paymentType)
{
case PaymentType.PayPalPayment:
paymentService = new PayPalPayment();
break;
case PaymentType.CreditCardPayment:
paymentService = new CreditCardPayment();
break;
default:
break;
}
return paymentService;
}
I thought of implementing this modules using strategy design pattern, and I got deviated from Strategy and ended up doing this way.
Is this a proper way for creating the payment modules. Is there a more better approach of solving this scenario. Is this a design pattern?
Edited:
Client Code:
static void Main(string[] args)
{
PaymentStrategy paymentStrategy = null;
paymentStrategy = new PaymentStrategy(GetPaymentOption((PaymentType)1));
paymentStrategy.Pay<PayPalModel>(new PayPalModel() { UserName = "", Password = "" });
paymentStrategy = new PaymentStrategy(GetPaymentOption((PaymentType)2));
paymentStrategy.Pay<CreditCardModel>(
new CreditCardModel()
{
CardHolderName = "Aakash"
});
Console.ReadLine();
}
Strategy:
public class PaymentStrategy
{
private readonly IPaymentService paymentService;
public PaymentStrategy(IPaymentService paymentService)
{
this.paymentService = paymentService;
}
public void Pay<T>(T type) where T : class
{
paymentService.MakePayment(type);
}
}
Does this update inlines with the Strategy Pattern?
One major drawback of using an abstract factory for this is the fact that it contains a switch case statement. That inherently means if you want to add a payment service, you have to update the code in the factory class. This is a violation of the Open-Closed Principal which states that entities should be open for extension but closed for modification.
Note that using an Enum to switch between payment providers is also problematic for the same reason. This means that the list of services would have to change every time a payment service is added or removed. Even worse, a payment service can be removed from the strategy, but still be an Enum symbol for it even though it isn't valid.
On the other hand, using a strategy pattern doesn't require a switch case statement. As a result, there are no changes to existing classes when you add or remove a payment service. This, and the fact that the number of payment options will likely be capped at a small double-digit number makes the strategy pattern a better fit for this scenario.
Interfaces
// Empty interface just to ensure that we get a compile
// error if we pass a model that does not belong to our
// payment system.
public interface IPaymentModel { }
public interface IPaymentService
{
void MakePayment<T>(T model) where T : IPaymentModel;
bool AppliesTo(Type provider);
}
public interface IPaymentStrategy
{
void MakePayment<T>(T model) where T : IPaymentModel;
}
Models
public class CreditCardModel : IPaymentModel
{
public string CardHolderName { get; set; }
public string CardNumber { get; set; }
public int ExpirtationMonth { get; set; }
public int ExpirationYear { get; set; }
}
public class PayPalModel : IPaymentModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
Payment Service Abstraction
Here is an abstract class that is used to hide the ugly details of casting to the concrete model type from the IPaymentService implementations.
public abstract class PaymentService<TModel> : IPaymentService
where TModel : IPaymentModel
{
public virtual bool AppliesTo(Type provider)
{
return typeof(TModel).Equals(provider);
}
public void MakePayment<T>(T model) where T : IPaymentModel
{
MakePayment((TModel)(object)model);
}
protected abstract void MakePayment(TModel model);
}
Payment Service Implementations
public class CreditCardPayment : PaymentService<CreditCardModel>
{
protected override void MakePayment(CreditCardModel model)
{
//Implementation CreditCardPayment
}
}
public class PayPalPayment : PaymentService<PayPalModel>
{
protected override void MakePayment(PayPalModel model)
{
//Implementation PayPalPayment
}
}
Payment Strategy
Here is the class that ties it all together. Its main purpose is to provide the selection functionality of the payment service based on the type of model passed. But unlike other examples here, it loosely couples the IPaymentService implementations so they are not directly referenced here. This means without changing the design, payment providers can be added or removed.
public class PaymentStrategy : IPaymentStrategy
{
private readonly IEnumerable<IPaymentService> paymentServices;
public PaymentStrategy(IEnumerable<IPaymentService> paymentServices)
{
this.paymentServices = paymentServices ?? throw new ArgumentNullException(nameof(paymentServices));
}
public void MakePayment<T>(T model) where T : IPaymentModel
{
GetPaymentService(model).MakePayment(model);
}
private IPaymentService GetPaymentService<T>(T model) where T : IPaymentModel
{
var result = paymentServices.FirstOrDefault(p => p.AppliesTo(model.GetType()));
if (result == null)
{
throw new InvalidOperationException(
$"Payment service for {model.GetType().ToString()} not registered.");
}
return result;
}
}
Usage
// I am showing this in code, but you would normally
// do this with your DI container in your composition
// root, and the instance would be created by injecting
// it somewhere.
var paymentStrategy = new PaymentStrategy(
new IPaymentService[]
{
new CreditCardPayment(), // <-- inject any dependencies here
new PayPalPayment() // <-- inject any dependencies here
});
// Then once it is injected, you simply do this...
var cc = new CreditCardModel() { CardHolderName = "Bob" /* Set other properties... */ };
paymentStrategy.MakePayment(cc);
// Or this...
var pp = new PayPalModel() { UserName = "Bob" /* Set other properties... */ };
paymentStrategy.MakePayment(pp);
Additional References:
Dependency Injection Unity - Conditional Resolving
Factory method with DI and IoC
This is one approach you could take. There's not a lot to go on from your source, and I'd really reconsider having MakePayment a void instead of something like an IPayResult.
public interface IPayModel { } // Worth investigating into common shared methods and properties for this
public interface IPaymentService
{
void MakePayment(IPayModel payModel);
}
public interface IPaymentService<T> : IPaymentService where T : IPayModel
{
void MakePayment(T payModel); // Void here? Is the status of the payment saved on the concrete pay model? Why not an IPayResult?
}
public class CreditCardModel : IPayModel
{
public string CardHolderName { get; set; }
}
public class PayPalModel : IPayModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
public class CreditCardPayment : IPaymentService<CreditCardModel>
{
public void MakePayment(CreditCardModel payModel)
{
//Implmentation CreditCardPayment
}
void IPaymentService.MakePayment(IPayModel payModel)
{
MakePayment(payModel as CreditCardModel);
}
}
public class PayPalPayment : IPaymentService<PayPalModel>
{
public void MakePayment(PayPalModel payModel)
{
//Implmentation PayPalPayment
}
void IPaymentService.MakePayment(IPayModel payModel)
{
MakePayment(payModel as PayPalModel);
}
}
public enum PaymentType
{
PayPalPayment = 1,
CreditCardPayment = 2
}
So following your implementation approach, it could look something like:
static class Program
{
static void Main(object[] args)
{
IPaymentService paymentStrategy = null;
paymentStrategy = GetPaymentOption((PaymentType)1);
paymentStrategy.MakePayment(new PayPalModel { UserName = "", Password = "" });
paymentStrategy = GetPaymentOption((PaymentType)2);
paymentStrategy.MakePayment(new CreditCardModel { CardHolderName = "Aakash" });
Console.ReadLine();
}
private static IPaymentService GetPaymentOption(PaymentType paymentType)
{
switch (paymentType)
{
case PaymentType.PayPalPayment:
return new PayPalPayment();
case PaymentType.CreditCardPayment:
return new CreditCardPayment();
default:
throw new NotSupportedException($"Payment Type '{paymentType.ToString()}' Not Supported");
}
}
}
I also think for a strategy/factory pattern approach, manually creating an IPayModel type doesn't make much sense. Therefore you could expand the IPaymentService as an IPayModel factory:
public interface IPaymentService
{
IPayModel CreatePayModel();
void MakePayment(IPayModel payModel);
}
public interface IPaymentService<T> : IPaymentService where T : IPayModel
{
new T CreatePayModel();
void MakePayment(T payModel);
}
public class CreditCardPayment : IPaymentService<CreditCardModel>
{
public CreditCardModel CreatePayModel()
{
return new CreditCardModel();
}
public void MakePayment(CreditCardModel payModel)
{
//Implmentation CreditCardPayment
}
IPayModel IPaymentService.CreatePayModel()
{
return CreatePayModel();
}
void IPaymentService.MakePayment(IPayModel payModel)
{
MakePayment(payModel as CreditCardModel);
}
}
Usage would then be:
IPaymentService paymentStrategy = null;
paymentStrategy = GetPaymentOption((PaymentType)1);
var payModel = (PayPalModel)paymentStrategy.CreatePayModel();
payModel.UserName = "";
payModel.Password = "";
paymentStrategy.MakePayment(payModel);
Your code is basically using the factory pattern. This is a good way to handle more than one method of payment
http://www.dotnettricks.com/learn/designpatterns/factory-method-design-pattern-dotnet

Beginner on Dependency Injection

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;
}
}

C# Model - Separation of concerns?

I have a model Administrator that has its properties, but it also consists of numerous static methods that do not really tied any way to the current object itself like for example GetByCredentials(string username, string password);. Is it somehow possible to divide static methods someplace else and lave object as pure as possible?
Example
public class Administrator : Entity
{
// OBJECT START
public int Id { get; set; }
public DateTime CreatedDateTime { get; set; }
public DateTime UpdatedDateTime { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string PasswordSalt { get; set; }
public void SetNewPassword(string password)
{
var cryptoService = new PBKDF2();
this.Password = cryptoService.Compute(password);
this.PasswordSalt = cryptoService.Salt;
}
public override void OnBeforeInsert()
{
this.CreatedDateTime = DateTime.Now;
this.UpdatedDateTime = DateTime.Now;
this.SetNewPassword(this.Password);
}
public override void OnBeforeUpdate()
{
this.UpdatedDateTime = DateTime.Now;
}
// OBJECT END
// Now I have multiple static methods that do not really
// have anything to do with current object
public static Administrator GetByCredentials(string username, string password)
{
var db = new MainDataContext();
var admin = db.Administrators.SingleOrDefault(x => x.Username == username);
if (admin == null) return null;
ICryptoService cryptoService = new PBKDF2();
var hash = cryptoService.Compute(password, admin.PasswordSalt);
if (hash == admin.Password) return admin;
return null;
}
public static bool IsCurrentIpBanned
{
get
{
const int minutesBlocked = 5;
const int maxLoginCount = 5;
var db = new MainDataContext();
var loginCount = db.AdministratorAuthorizationLogs.AsEnumerable().Count(x => x.Ip == HttpContext.Current.Request.UserHostAddress && x.CreatedDateTime.AddMinutes(minutesBlocked) > DateTime.Now && x.IsSuccess == false);
return loginCount > maxLoginCount;
}
}
public static void LogSuccess(Administrator admin)
{
Administrator.Log(admin, true);
}
public static void LogFailure(Administrator admin)
{
Administrator.Log(admin, false);
}
private static void Log(Administrator admin, bool success)
{
var db = new MainDataContext();
db.AdministratorAuthorizationLogs.Add(new AdministratorAuthorizationLog
{
Username = admin.Username,
Password = admin.Password,
Ip = HttpContext.Current.Request.UserHostAddress,
IsSuccess = success
});
db.SaveChanges();
}
}
There are several options here, but the main thing is that C# classes are the tool for separating concerns.
The most obvious is to capture those things in their own abstraction(s). For example, the GetByCredentials might be better as a (non-static) member of a different class Authority or similar. That class only needs to be able to create an Administrator type.
You can also use extension methods. A possible candidate for that is Log, which takes an Administrator as an argument and uses only public facilities on it. Extension methods are defined in a separate class, but allow you to use them "as if" they were members of the extended class, e.g.:
public static class AdministratorExtensions
{
public static void log( this Administrator admin, bool success ) { ... }
}
var admin = new Administrator();
admin.Log( true );
The key thing is to identify real abstractions and build your system up from them by combining them in sensible ways. Separating out concerns is part of that process.
This is a hint that your class "knows too much". The Administrator class should only know what concerns an administrator. He shouldn't be able to query the database and retrieve entities.
You should look into the repository pattern. Try to decompose your application into multiple layers. For example, you could have a DataRepository class whose main concern is to query and update the database entities.

Unity IoC and Static method

What is the best way to handle a situation where you're using IoC but there is a static method in it along with the other methods like the following:
public partial class ShoppingCart
{
private IDatabaseFactory _storeDB;
public ShoppingCart(IDatabaseFactory storeDB)
{
_storeDB = storeDB;
}
private string ShoppingCartId { get; set; }
public static ShoppingCart GetCart(HttpContextBase context)
{
var cart = new ShoppingCart(WHATGOESHERE?);
cart.ShoppingCartId = cart.GetCartId(context);
return cart;
}
public int OtherMethod()
{
...
}
}
The static GetCart method is an Ambient Context. It's a bad idea, especially to have such a method at the level of your domain model. Try refactoring it to an abstract factory:
public interface IShoppingCartFactory
{
ShoppingCart GetCartForCurrentUser();
}
You can inject the IShoppingCartFactory in services that need it (but not in your entities, it's better to keep your entities clean). Now you can define an implementation and register it in your IoC configuration. Here's an example of such an implementation:
public class HttpShoppingCartFactory : IShoppingCartFactory
{
private readonly IShoppingUnitOfWorkFactory uowFactory;
public HttpShoppingCartFactory(
IShoppingUnitOfWorkFactory uowFactory)
{
this.uowFactory = uowFactory;
}
public ShoppingCart GetCartForCurrentUser()
{
int userId = (int)HttpContext.Current.Session["userId"];
using (var unitOfWork = this.uowFactory.CreateNew())
{
return unitOfWork.ShoppingCards
.FirstOrDefault(c => c.User.Id == userId);
}
}
}
It would be even better to separate the getting the user context from the shopping card factory. For instance, you yould inject a IUserContextFactory in the shopping card factory, making it independant on ASP.NET.
IMO you should refactor it, making it to look like this:
public class ShoppingCartService {
private readonly IDatabaseFactory _storeDB;
public ShoppingCartService(IDatabaseFactory storeDB) {
_storeDB = storeDB
}
public ShoppingCart GetCart(IdType cartId)
{
var cart = new ShoppingCart(_storeDB);
cart.ShoppingCartId = cartId;
return cart;
}
}
public partial class ShoppingCart
{
private IDatabaseFactory _storeDB;
public ShoppingCart(IDatabaseFactory storeDB)
{
_storeDB = storeDB;
}
private string ShoppingCartId { get; set; }
public int OtherMethod()
{
...
}
}
This way, you are moving responsibility to get the current shopping cart from a static method to a service class you can inject in the presentation layer.

Is It possible to use the second part of this code for repository patterns and generics

Is there any issues in using version 2,to get the same results as version 1.
Or is this just bad coding.
Any Ideas
public class Customer
{
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
int Age { get; set; }
}
public interface ICustomer
{
void AddNewCustomer(Customer Customer);
void AddNewCustomer(string EmailAddress, int Age);
void RemoveCustomer(Customer Customer);
}
public class BALCustomer
{
private readonly ICustomer dalCustomer;
public BALCustomer(ICustomer dalCustomer)
{
this.dalCustomer = dalCustomer;
}
public void Add_A_New_Customer(Customer Customer)
{
dalCustomer.AddNewCustomer(Customer);
}
public void Remove_A_Existing_Customer(Customer Customer)
{
dalCustomer.RemoveCustomer(Customer);
}
}
public class CustomerDataAccess : ICustomer
{
public void AddNewCustomer(Customer Customer)
{
// MAKE DB CONNECTION AND EXECUTE
throw new NotImplementedException();
}
public void AddNewCustomer(string EmailAddress, int Age)
{
// MAKE DB CONNECTION AND EXECUTE
throw new NotImplementedException();
}
public void RemoveCustomer(Customer Customer)
{
// MAKE DB CONNECTION AND EXECUTE
throw new NotImplementedException();
}
}
// VERSION 2
public class Customer_New : DataRespository<CustomerDataAccess>
{
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
public int Age { get; set; }
}
public class DataRespository<T>
where T:class,new()
{
private T item = new T();
public T Execute { get { return item; } set { item = value; } }
public void Update()
{
//TO BE CODED
}
public void Save()
{
//TO BE CODED
}
public void Remove()
{
//TO BE CODED
}
}
class Program
{
static void Main(string[] args)
{
Customer_New cus = new Customer_New()
{
Age = 10,
EmailAddress = "this#demo.com"
};
cus.Save();
cus.Execute.RemoveCustomer(new Customer());
// Repository Version
Customer customer = new Customer()
{
EmailAddress = "new#demo.com",
CustomerID = 10
};
BALCustomer bal = new BALCustomer(new CustomerDataAccess());
bal.Add_A_New_Customer(customer);
}
}
You have a lot of things going on that aren't making a lot of sense.
First of all, the names of properties should always be a noun (singular or plural) or a "being" verb like Is* or Has*. These are properties of an object, and should be similar to what you would say in response to a question like "Would you please describe your desk?" Execute is an operation, and should therefore be a method. Likewise, your naming conventions in Version 1 should be PascalCased which means no underscores and the first letter of all words should be capitalized. These aren't die-hard truths, but they are considered OOP common C# coding standards.
Secondly, the code in your main method isn't actually implementing anything in your generic class. The only thing your class is actually doing is creating an instance of CustomerDataAccess. The Save() method won't do anything, unless you specifically are able to call item.Save() In order to use your Save, Update, Delete functionality on your generic class, your CustomerDataAccess class will have to implement an interface expected by your generic class. For instance:
public interface IDataAccess<T> : where T : YourBaseObject {
public void Update(T item);
public void Save(T item);
public void Remove(T item);
}
public class Customer : YourBaseObject {
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
public int Age { get; set; }
}
public class CustomerDataAccess :
DataRespository<IDataAccess<Customer>> {
public void PerformCustomerOnlyAction(Customer customer) {
/* do stuff */
}
}
Now, you can create a generic class that handles basic CRUD functionality, and all other functionality is accessible through the BaseRepository property.
/* e.g. T = IDataAccess<Customer>, K = Customer */
public class DataRespository<T>
where T : IDataAccess<K>, new()
where K : YourBaseObject, new()
{
private T _base;
public T BaseRepository {
get {
if(_base == null)
_base = Activator.CreateInstance<T>();
return _base;
}
}
public void Update(K item) { /* functionality for YourBaseObject */ }
public void Save(K item) { /* functionality for YourBaseObject */ }
public void Remove(K item) { /* functionality for YourBaseObject */ }
}
class Program
{
static void Main(string[] args)
{
var repository = new CustomerDataAccess();
Customer c = new Customer {
Age = 10,
EmailAddress = "this#demo.com"
};
repository.Save(c);
// This pass-through is no longer needed, but shown as example
// repository.BaseRepository.PerformCustomerOnlyAction(c);
repository.PerformCustomerOnlyAction(c);
}
}
NOTE I did the above code from scratch/memory. The generic type constraints may not work exactly as I have them.
ASP.NET 3.5 Unleashed by Stephen Walther has a couple of chapters on creating a repository pattern which is setup similarly to what you're trying to accomplish in Version 2. He also splits processing up between a business logic layer and a data access layer. Although the book is huge (nearly 2000 pages) and many of the code examples are redundant or better left as part of the CD, he goes pretty in-depth for beginner-to-intermediate range. It's available used on Amazon for around $25.
I think while implementing object model of your application you just have to ask yourself a number of questions as though you are make object design review of your collegue code.
Why CustomerAccessLayer implements interface? Is there will be a number of layers implementing this Interface. Or maybe you are expecting any polymorph behaviour from classes implements this interface? Or maybe you will separate interface to standalone module and will provide its functionality though any kind of service?
Why do you need BALCustomer class? Why you could not make calls directly to CustomerAccesLayer? And, have i already spoke about codesyle? :)
If DataRepository have a generic behaviour and will provide a number of AccessLayers throw Execute property why it is have its own methods?
I think could be continued... I hope you've catch my point?

Categories

Resources