I am trying to learn design patterns in C# and my friend has written me some code for an Abstract factory pattern (I think).
from what I am seeing the code creates a factory(Fa),
this factory(Fa) then creates another factory(Fb) based on an Enum and then that factory(Fb) creates a concrete class that can be used to call an API etc.
I can create a factory(Fb) and it creates the class but when I call methods from the class that were created by the factory(fb), I do not see my methods and cant call them but can only call the class that it inherits.
What I am trying to do in a nutshell, is create a factory that creates Jane dolls (like it does) and this inherits everything from the doll class, it also has all its own properties, great, but why cant I access its own properties when I make a factory to create the Jane Factory, it only lets me use the inherited Doll methods this way, but if I created another factory to create Santa dolls it would have different methods I need to use.
**Web.Controllers
**
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Qqq.Dolls.Web.Controllers
{
public class InventoryController : Controller
{
private readonly IDollFactory _dollFactory;
private readonly IJaneDollFactory _janeDollFactory;
private readonly IMapper _mapper;
public InventoryController(IJaneDollFactory dollFactory, IMapper mapper, IDollFactory dollFactory1)
{
_janeDollFactory = dollFactory;
_mapper = mapper;
_dollFactory = dollFactory1;
}
public async Task<IActionResult> List()
{
var token = HttpContext.Session.GetObject<OAuthResponse>(SessionConstants.JaneToken);
var doll = _JaneDollFactory.Create(token, JaneScopeConstants.GetAllScopes());
var a = _DollFactory.Create(Doll.Jane, HttpContext);
var ab = await a.LGetProductAsync("TestProduct");
var inventory = await doll.GetInventory();
var ret = inventory.InventoryItems.Select(
inventoryItem => _mapper.Map<InventoryViewModel>(inventoryItem));
return View(ret);
}
}
}
DollFactory
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Qqq.Dolls.Web.Infrastructure;
public class DollFactory : IDollFactory
{
private readonly IJaneDollFactory _JaneDollFactory;
public DollFactory(IJaneDollFactory JaneDollFactory)
{
_JaneDollFactory = JaneDollFactory;
}
public IDoll Create(Doll Doll, HttpContext httpContext)
{
switch (Doll)
{
case Doll.Jane:
var token = httpContext.Session.GetObject<OAuthResponse>(SessionConstants.JaneToken);
return _JaneDollFactory.Create(token, JaneScopeConstants.GetAllScopes());
default:
throw new NotImplementedException();
}
}
}
IJaneDollFactory Interface
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Qqq.Dolls.Jane;
public interface IJaneDollFactory
{
IJaneDoll Create(OAuthResponse oAuthResponse, List<string> scopes, HttpMessageHandler httpMessageHandler = null);
}
**IJaneDoll interface **
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Qqq.Dolls.Jane;
public interface IJaneDoll : IDoll
{
//Inventory
Task<Inventory> GetInventory();
Task ListInventoryItem(InventoryItem product);
Task DeleteInventoryItem(string sku);
}
IDoll interface
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public interface IDoll
{
Task ListProductAsync(Product product);
Task<Product> GetProductAsync(string productId);
}
interface IDollFactory
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Qqq.Dolls.Web.Infrastructure;
public interface IDollFactory
{
IDoll Create(Doll doll, HttpContext httpContext);
}
JaneDollFactory
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Qqq.Dolls.Jane;
public class JaneDollFactory : IJaneDollFactory
{
private readonly IMapper _mapper;
private readonly JaneApiConfiguration _JaneApiConfiguration;
public JaneDollFactory(IOptions<JaneApiConfiguration> JaneApiConfiguration, IMapper mapper)
{
_mapper = mapper;
_JaneApiConfiguration = JaneApiConfiguration.Value;
}
public IJaneDoll Create(OAuthResponse oAuthResponse, List<string> scopes, HttpMessageHandler httpMessageHandler = null)
{
return new JaneDoll(_mapper, _JaneApiConfiguration, oAuthResponse, scopes, httpMessageHandler);
}
}
This is happening is because in you factory create method you have the return type as
IDoll
So when you create a doll, no matter what doll you instantiate, it gets implicitly casted into an IDoll (this is the mistake in DollFactory class)
Since your caller knows what doll it wants the abstract factory to create, when you retrieve the object you can explicitly cast it to an IJaneDoll
var a = (IJaneDoll) _DollFactory.Create(Doll.Jane, HttpContext);
This should allow you to access members from both IDoll and IJane doll.
Related
ASP.NET Core 5 MVC application gets translations in from table at runtime. EF Core async methods are used to implement IStringLocalizer interface.
The code shown below causes compile-time error:
The modifier 'async' is not valid for this item
on this line
public async LocalizedString this[string name] => new LocalizedString(name, await I(name));
How to implement IStringLocalizer interface using EF Core async data access?
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// Translation service.
/// Retrieves localized strings from database
/// </summary>
public sealed class Localizer : IStringLocalizer
{
readonly EevaContext ctx;
public Localizer(EevaContext ctx)
{
this.ctx = ctx;
}
async Task<string> I(string str)
{
return await ctx.Strings
.Where((s) => s.Est == estString.)
.SingleOrDefaultAsync();
}
#region interface implementation
public async LocalizedString this[string name] => new LocalizedString(name, await I(name));
public LocalizedString this[string name, params object[] arguments] => throw new NotImplementedException();
}
Answer in async Indexer in C# states that indexer can return Task . Maybe this can used.
Here is Repository pattern, Normally if I used ContextDb instead of IdentityContextDb ,it would have worked but i have to use Indentity for creating my Identificial things.
Core.Repository
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace XYZ.CORE.Repository
{
public class Repository<TEntity, TContext> : IRepository<TEntity> where
TEntity : class, new() where TContext : IdentityDbContext, new()
{
public void Delete(TEntity entity)
{
using (var context=new TContext())
{
var deleteEntity = context.Entry(entity);
deleteEntity.State = EntityState.Deleted;
context.SaveChanges();
}
}
public IEnumerable<TEntity> GetAll(Expression<Func<TEntity, bool>> filter = null)
{
using (var context = new TContext())
{
return filter == null ? context.Set<TEntity>().AsEnumerable() : context.Set<TEntity>().Where(filter).AsEnumerable();
}
}
public TEntity GetById(int id)
{
using (var context = new TContext())
{
return context.Set<TEntity>().Find(id);
}
}
public void Insert(TEntity entity)
{
using (var context = new TContext())
{
var addEntity = context.Entry(entity);
addEntity.State = EntityState.Added;
context.SaveChanges();
}
}
public void Update(TEntity entity)
{
using (var context = new TContext())
{
var updatedEntity = context.Entry(entity);
updatedEntity.State = EntityState.Modified;
context.SaveChanges();
}
}
}
}
again but :) when i inherit my context from IdentityContextDb, it wants generic type like bottom of this line and its problem for Repository.
i'll share what is like an error when we call this Repo
DAL.Context
using XYZ.DATA.Entity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
namespace XYZ.DAL.Context
{
public class XyzDb:IdentityDbContext<AppUser>
{
public HysWebDb(DbContextOptions options) : base(options)
{
}
}
}
and now lets call in Controller
UI.Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using XYZ.UI.Models.VM;
using Microsoft.AspNetCore.Mvc;
using XYZ.DAL.Context;
using Microsoft.AspNetCore.Identity;
using XYZ.DATA.Entity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Authorization;
using XYZ.CORE.Repository;
namespace XYZ.UI.Controllers.Account
{
//[Authorize(Roles ="Admin")]
public class RegisterController : Controller
{
private readonly XyzDb _database;
private readonly UserManager<AppUser> _uManager;
private readonly Repository<AppUser,XyzDb> _userRepo;
public RegisterController(UserManager<AppUser> uManager, XyzDb database)
{
_database = database;
_uManager = uManager;
}
}
}
although we havent injected yet but ...
Error CS0311 The type 'XYZ.DAL.Context.XyzDb' cannot be used as type parameter 'TContext' in the generic type or method
'Repository'. There is no implicit reference
conversion from 'XYZ.DAL.Context.XyzDb' to
'Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext'. ~\XYZ.UI\Controllers\Account\RegisterController.cs 21 Active
Error CS0310 'XyzDb' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TContext'
in the generic type or method 'Repository' ~\XYZ.UI\Controllers\Account\RegisterController.cs 21 Active
Line 21 is here private readonly Repository
_userRepo;
Thanks,
Özgür
public class Repository<TEntity, TContext> : IRepository<TEntity> where
TEntity : class, new() where TContext : IdentityDbContext, new()
You are defining here two things:
The repository class must use class there TEntity & TContext has new() which means parameterless constructor, when in fact you have only 1 constructor with options - (this is your 2nd error)
public HysWebDb(DbContextOptions options) : base(options)
The second problem not 100% sure about this but if you inherit a generic interface but declare the type - IdentityDbContext - it cannot be considered as only IdentityDbContext
public class XyzDb:IdentityDbContext < AppUser>
To solve your problem you should change the public class Repository to this:
public class Repository<TEntity, TContext> : IRepository<TEntity> where
TEntity : class, new() where TContext : IdentityDbContext<AppUser>
Actually you're setting a constraint on your generic Repository class
public class Repository<TEntity, TContext> : IRepository<TEntity> where
TEntity : class, new() where TContext : IdentityDbContext, new()
which is the new() on your IdentityDbContext, so your IdentityDbContext should contains a parameterless constructor.
For more details check microsoft docs https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/new-constraint
I can solve with using context referance and injection in constructor
public class Repository<T> : IRepository<T> where T : class
{
private readonly ContextX _database;
public Repository(ContextX database)
{
_database = database;
}
we cant find another way for solution
Thanks,
Özgür Deniz
I am new to .NET. I am create a internet shop but i have a problems
My Error:
Error activating IBookRepository No matching bindings are
available, and the type is not self-bindable. Activation path: 2)
Injection of dependency IBookRepository into parameter repo of
constructor of type BooksController 1) Request for BooksController
Suggestions: 1) Ensure that you have defined a binding for
IBookRepository. 2) If the binding was defined in a module, ensure
that the module has been loaded into the kernel. 3) Ensure you have
not accidentally created more than one kernel. 4) If you are using
constructor arguments, ensure that the parameter name matches the
constructors parameter name. 5) If you are using automatic module
loading, ensure the search path and filters are correct.
I using 3 project in Solution I have a interface IBookRepository in c# Class Library Domain and using asp.net mvc in controller
IBookRepository:
using Domain.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Domain.Abstract
{
public interface IBookRepository
{
IEnumerable<Book> Books { get; }
}
}
BooksController:
using Domain.Abstract;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace WebUI.Controllers
{
public class BooksController : Controller
{
private IBookRepository repository;
public BooksController(IBookRepository repo)
{
repository = repo;
}
public ViewResult List()
{
return View(repository.Books);
}
}
}
I have a bindings for all the constructor parameter types:
private static void RegisterServices(IKernel kernel)
{
System.Web.Mvc.DependencyResolver.SetResolver(new WebUI.Infrastructure.NinjectDependencyResolver(kernel));
}
How can I fix this problem?
So you have the first step of dependency injection down, but you need to tell your code what concrete class to use when your interface is requested. To do that you need to create a binding for your concrete class.
To do this you need to navigate to your Ninject bindings file and add this:
Bind<IBookRepository>().To<NameOfYourClassThatImplementsIBookRepository>();
Obviously NameOfYourClassThatImplementsIBookRepository should be replaced with the actual name of your concrete class (i.e the class that implements your interface).
I am not aware of Ninject, but looking at the code above, BookController constructor needs an instance of class which implements IBookRepository. Think of constructor chaining or have one more default constructor to pass instance to above written constructor.
using Domain.Abstract;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace WebUI.Controllers
{
public class BooksController : Controller
{
private IBookRepository repository;
public BooksController():this(new BookRepository())
{
}
public BooksController(IBookRepository repo)
{
repository = repo;
}
public ViewResult List()
{
return View(repository.Books);
}
}
}
A bit rusty here with regards to WCF Services.
I have a custom class named cSecurity.cs which does some custom functions.
I want to use this custom class inside my Service:
This is the App.svc.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace AppServices
{
public class App : IApp
{
public cSecurity _csec;
public string GetItems(int agentID, string agentName)
{
// Need to use some functions from the cSecurity class here???
return _csec.getItems();
}
}
}
This is the cSecurity.cs class:
using System.Collections;
using System.Configuration;
using System.Net;
namespace AppServices
{
public class cSecurity
{
// Some functions defined here....
public string getItems(){
return string.Empty;
}
}
}
But I am getting an error on the line:
public cSecurity _csec;
"The type or namespace name 'cSecurity' could not be found."
This seems pretty trivial but I seem to be lost here.
Appreciate any insight. Thanks.
For some reason, the solution for this was for me to close and restart VS. Not sure what caused the class for it to be not referenced by VS.
I was following the example (Aggressive old mode) given in:
http://docs.castleproject.org/Default.aspx?Page=Startable-Facility&NS=Windsor&AspxAutoDetectCookieSupport=1
Here is my full source code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Castle.Facilities.Startable;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
namespace Test
{
public interface IStartable
{
void Start();
void Stop();
}
public class Startable : IStartable
{
public Startable()
{
Console.WriteLine("Created!");
}
public void Start()
{
Console.WriteLine("Started!");
}
public void Stop()
{
Console.WriteLine("Stopped!");
}
}
[TestFixture]
public class StartableFacilityContainerTest
{
[Test]
public void TestOperation()
{
IKernel container = new DefaultKernel();
container.AddFacility<StartableFacility>();
container.Register(Component.For<Startable>());
Console.WriteLine("Registered!");
container.Dispose();
Console.WriteLine("Released!");
}
}
}
However when I run it, I get:
Registered!
Released!
when I expect to get (as given in the example):
Created!
Started!
Registered!
Stopped!
Released!
Basically my Startable did not start.
This is tested in .Net 4.0 and Castle Windsor 3.0
What did I do wrong?
I'm using Installers. This helped me:
container.AddFacility<StartableFacility>(f => f.DeferredTryStart());
try
container.Register(Component.For<Startable>()
.StartUsingMethod(s => s.Start)
.StopUsingMethod(s => s.Stop);
The problem is you have created and implemented your own IStartable interface instead of just implementing the Castle.Core.IStartable