interface IState {
}
class GoodState: IState {}
class BadState: IState {}
class MoreState: IState {}
// I stuck at here... :(
interface StateAggregateService {
IState GoodState {get;}
IState BadState {get;}
IState MoreState {get;}
}
Basically, I want to implement the State Machine pattern. I want to use the autofac aggregate service extension to create a factory class for me automatically. But all the concrete state classes inherit from the IState interface, the aggregate service extension cannot distinguish them.
One walkaround is to define some dummy interface like IGoodState which inherits from IState. The problem is that as the number of state classes increase, so do the number of dummy interfaces, and I feel it is really a dumb idea.
Is there's a way to associate registration with the property name, or something like that?
One way would be to use Named registration for your IState implementation and use property injection for the class implementing IStateAggregateService. So for aggregate service you would have:
interface IStateAggregateService
{
IState GoodState { get; }
IState BadState { get; }
IState MoreState { get; }
}
class StateAggregateService : IStateAggregateService
{
public IState GoodState { get; set; }
public IState BadState { get; set; }
public IState MoreState { get; set; }
}
and the registration would look like the following:
builder.RegisterType<GoodState>().Named<IState>("GoodState");
builder.RegisterType<BadState>().Named<IState>("BadState");
builder.RegisterType<MoreState>().Named<IState>("MoreState");
builder.Register(c => new StateAggregateService
{
GoodState = c.ResolveNamed<IState>("GoodState"),
BadState = c.ResolveNamed<IState>("BadState"),
MoreState = c.ResolveNamed<IState>("MoreState")
}).As<IStateAggregateService>();
Keep in mind this approach would return the same object every time you call a property from aggregate service.
If you want fresh instance every time you call a property, you could use different approach with keyed registration and IIndex<TKey, TService> interface; the registration would look like this:
builder.RegisterType<GoodState>().Keyed<IState>("GoodState");
builder.RegisterType<BadState>().Keyed<IState>("BadState");
builder.RegisterType<MoreState>().Keyed<IState>("MoreState");
builder.RegisterType<StateAggregateService>().As<IStateAggregateService>();
and implementation of the service
class StateAggregateService : IStateAggregateService
{
private readonly IIndex<string, IState> _states;
public IState GoodState => _states["GoodState"];
public IState BadState => _states["BadState"];
public IState MoreState => _states["MoreState"];
public StateAggregateService(IIndex<string, IState> states)
{
_states = states;
}
}
To make this approach cleaner, you might want to use some enum as a key for your IState implementations instead of string.
Also, you could just get rid of StateAggregateService and use IIndex<TKey, TService> as a factory wherever you need.
Updated:
As stated in comment, it's true, the solution you need is not possible to be achieved with Aggregated Service. But it's possible to do something similar with some manual registration and reflection. For the following interface and aggregator class:
interface IStateAggregateService
{
IState GoodState { get; }
IState BadState { get; }
IState MoreState { get; }
}
class StateAggregateService : IStateAggregateService
{
public IState GoodState { get; set; }
public IState BadState { get; set; }
public IState MoreState { get; set; }
}
you could use the following registration:
builder.RegisterType<GoodState>().Keyed<IState>("GoodState");
builder.RegisterType<BadState>().Keyed<IState>("BadState");
builder.RegisterType<MoreState>().Keyed<IState>("MoreState");
builder.Register(c =>
{
var serviceProps = typeof(StateAggregateService).GetProperties();
var service = new StateAggregateService();
foreach (var property in serviceProps)
{
property.SetValue(service, c.ResolveKeyed<IState>(property.Name));
}
return service;
}).As<IStateAggregateService>();
The difference is you need to create a class implementing your aggregation interface. This solution uses properties names so you need to keep their names the same as types, or prepare your own logic to assign proper implementation to aggregator properties.
Related
Having some issues getting my repository to retrieve information - keeps coming back null. Any Thoughts would be appreciated - new to this and teaching myself.
Repository:
public class CustomerRepository : ICustomerRepository
{
private masterContext context;
public CustomerRepository(masterContext context)
{
this.context = context;
}
public IEnumerable<Customer> GetCustomers()
{
return context.Customer.ToList();
}
public Customer GetCustomerById(int customerId)
{
var result = (from c in context.Customer where c.CustomerId == customerId select c).FirstOrDefault();
return result;
}
public void Save()
{
context.SaveChanges();
}
Controller:
public class CustomerController : Controller
{
private readonly ICustomerRepository _repository = null;
public ActionResult Index()
{
var model = (List<Customer>)_repository.GetCustomers();
return View(model);
}
public ActionResult New()
{
return View();
}
}
MasterContext which i had efc make:
public partial class masterContext : DbContext
{
public masterContext(DbContextOptions<masterContext> options)
: base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>(entity =>
{
entity.Property(e => e.CustomerName).IsRequired();
});
}
public virtual DbSet<Customer> Customer { get; set; }
public virtual DbSet<Order> Order { get; set; }
}
I think you need to create instances of you Context and your Repository. So in your Controller you need to something like this:
private masterContext context = new masterContext();
private ICustomerRepository repository = new CustomerRepository(context);
I assume that you're not using Dependency injection ... if so you just need to create a Constructor for your Controller that takes CustomerRepository as argument:
public CustomerController(ICustomerRepository _repository) {
repository = _repository;
}
If you did not configure your database context, look here: https://docs.efproject.net/en/latest/platforms/aspnetcore/new-db.html
This will than enable you the dependency injection. Everything you than need to do for the Repository is to use
services.AddScoped<ICustomerRepository,
CustomerRepository>();
And I think it could be good to remove the ToList() in the Repository class and remove the Cast List<Customer> in your Controller and use ToList() instead, if it's really needed. Because if you're using it in the View the ienumerable could also work.
I've been having a problem with this for about a day now, I've searched and found similar problems with their solutions but haven't been able to fix this.
I've seen this done with the Teams example, so I'll do the same. I have a Team:
public abstract class Team
{
[Key]
public int IdTeam { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
I also have a Match object:
public class Match
{
[Key]
public int IdMatch { get; set; }
[ForeignKey("HomeTeam")]
public int IdHomeTeam { get; set; }
[ForeignKey("AwayTeam")]
public int IdAwayTeam { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team AwayTeam { get; set; }
}
Whenever I try to access the name of either team I get an Invalid column name Team_TeamId error. I'm guessing it has something to do with EF and the Foreign Keys not being mapped correctly. I've also seen other people use ICollections, but I don't think I need them for this case.
You have to fix this in the OnModelCreating method. Entity framework can't seem to recognize the foreign keys, so you have to specify it specifically.
public class Entities : DbContext
{
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Match>()
.HasRequired(b => b.AwayTeam)
.WithMany()
.HasForeignKey(b => b.IdAwayTeam);
modelBuilder.Entity<Match>()
.HasRequired(b => b.HomeTeam)
.WithMany()
.HasForeignKey(b => b.IdHomeTeam);
}
}
for more information about code first OnModelCreating check this: http://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext.onmodelcreating(v=vs.103).aspx
I have two interfaces and I'm confused about the naming conventions:
interface InterfaceA {
IDbSet<Patient> Patients { get; }
// others like above
}
interface InterfaceB : InterfaceA {
int Commit();
}
class DbContext : InterfaceB {
public IDbSet<Patient> Patients { get; set; }
int Commit() {
return this.SaveChanges();
}
}
I don't want to confuse the other coders on my team. Which interface is the unit of work and which one is the repository?
InterfaceA is the repository.
Reason:
A repository is responsible for persisting data, and InterfaceB has no concept of data to be persisted.
I designing an applications which basically has 3 different logic layers:
DB connector (implemented by ADO.NET).
BL the business logic (the only thing the UI knows).
DB repositories (connects between the first two).
The DB repositories are separated into sections of dependency and every final entity is polymorphic to one interface. In some cases there are dependencies between objects inside the same dependency sections - ISectionFactory (hence dependent).
In practice the BL is going to ask for an object of specific type (such as IngrediantType in my example) from the MainFactory (which is a factor for all the DB)
Because of this design I am forced to cast types on the UI - which obviously is a drag.
How can I change the design ?
Here is a brief look of design:
public class MainFactory
{
private Dictionary<Type, ISectionFactory> m_SectionsFactories;
private ISectionFactory treatmentsSectionFactory =
new TreatmentsSectionFactory();
public MainFactory()
{
m_SectionsFactories = new Dictionary<Type, ISectionFactory>
{
{typeof(IngrediantType),treatmentsSectionFactory}
};
}
public IConcreteDataCollection GetConcreteData(Type i_EntitiesName)
{
return m_SectionsFactories[i_EntitiesName]
.GetConcreteData(i_EntitiesName);
}
}
internal interface ISectionFactory
{
IConcreteDataCollection GetConcreteData(Type i_EntitiesName);
}
public class TreatmentsSectionFactory : ISectionFactory
{
private Dictionary<Type, IConcreteDataCollection>
m_ConcreteDataCollections;
private IngrediantTypes m_IngrediantTypes = new IngrediantTypes();
private Ingrediants m_Ingrediants = new Ingrediants();
public TreatmentsSectionFactory()
{
m_ConcreteDataCollections =
new Dictionary<Type, IConcreteDataCollection>();
m_ConcreteDataCollections
.Add(typeof(IngrediantType), m_IngrediantTypes);
m_ConcreteDataCollections
.Add(typeof(Ingrediants), m_Ingrediants);
}
public IConcreteDataCollection GetConcreteData(Type i_EntitiesName)
{
return m_ConcreteDataCollections[i_EntitiesName];
}
}
public interface IConcreteDataCollection : IEnumerable
{
// Iteratable.
IConcreteData GetById(int i_Id);
void AddNewConcreteData(IConcreteData i_ConcreteData);
void UppdateConcreteData(IConcreteData i_ConcreteData);
void DeleteConcreteData(IConcreteData i_ConcreteToDelete);
}
public class IngrediantTypes : IConcreteDataCollection
{
public string TestType { get; set; }
public IConcreteData GetById(int i_Id){}
public void AddNewConcreteData(IConcreteData i_ConcreteData){}
public void UppdateConcreteData(IConcreteData i_ConcreteData){}
public void DeleteConcreteData(IConcreteData i_ConcreteToDelete){}
public IEnumerator GetEnumerator(){}
}
// also implements IConcreteDataCollection
public class Ingrediants : IConcreteDataCollection
{
}
public interface IConcreteData
{
public int Index { set; get; }
} // the final (highest) entity of all DB entities
public class IngrediantType : IConcreteData
{
public int Index { set; get; }
// other set of properties
}
public class Ingrediant : IConcreteData
{
public int Index { set; get; }
public IngrediantType RelatedIngrediantType { set; get; }
// other set of properties
}
public class mainClass
{
public static void main()
{
MainFactory factory = new MainFactory();
var type = typeof(IngrediantType);
// returns a IngrdiantTypes of type (IConcreteDataCollection)
var t = factory.GetConcreteData(typeof(IngrediantType));
// I want to use the IngrediantType without casting !!!
var s = t.GetById(2);
}
}
It's a little hard to tell what's going on here, but I think the key will be to take advantage of generics like so:
public IConcreteDataCollection<T> GetConcreteData<T>()
{
return ...;
}
If I understand your question correctly, this will allow you to say:
var t = factory.GetConcreteData<IngrediantType>();
You will need to change almost every class in your code to use generics.
Not sure if it has been asked before, here is the question.
Code first:
public class Customer {
public string Password { get; set; }
public string PasswordHash { get; set; }
}
public class CustomerService {
private ICustomerRepository _repo;
public CustomerService(ICustomerRepository repo) {
_repo = repo;
}
public int? AddCustomer(Customer customer) {
customer.PasswordHash = SHA1Hasher.ComputeHash(customer.Password);
return _repo.Add(customer);
}
}
public interface ICustomerRepository {
int? Add(Customer c);
}
public class CustomerRepository : ICustomerRepository {
int? AddCustomer(Customer customer) {
// call db and return identity
return 1;
}
}
[TestClass]
public class CustomerServiceTest {
[TestMethod]
public void Add_Should_Compute_Password_Hash_Before_Saving() {
var repoMock = new Mock<ICustomerRepository>();
//how do I make sure the password hash was calculated before passing the customer to repository???
}
}
How do I verify that CustomerService assigned the PasswordHash before passing the customer to repository?
There are several approaches you could take. Although not necessarily the best solution, here's one that doesn't require you to change your existing API. It assumes that SHA1Hasher.ComputeHash is a public method.
[TestClass]
public class CustomerServiceTest
{
[TestMethod]
public void Add_Should_Compute_Password_Hash_Before_Saving()
{
var customer = new Customer { Password = "Foo" };
var expectedHash = SHA1Hasher.ComputeHash(customer.Password);
var repoMock = new Mock<ICustomerRepository>();
repoMock
.Setup(r => r.Add(It.Is<Customer>(c => c.PasswordHash == expectedHash)))
.Returns(1)
.Verifiable();
// invoke service with customer and repoMock.Object here...
repoMock.Verify();
}
}
A slightly better solution would be to turn the SHA1Hasher into an injected service (such as IHasher) so that you can confirm that the PasswordHash property was assigned the value created by the IHasher instance.
Opening op your API even more, you could make the PasswordHash property virtual, so that you could pass a Mock Customer to the AddCustomer method to verify that the property was correctly set.
You could make SHA1Hasher non-static and virtual or wrap it in a ISHA1Hasher interface which can then be mocked. Wrapping static methods and objects in mockable classes is a classic way to increase testability.