Xamarin Forms dependency service don't work with generics? - xamarin

I'm trying to get an instance of generic class in Xamarin.Forms. If I use the code below everything works fine:
Interface
namespace PrismNinjectApp1.Application.Interfaces
{
public interface IUserService { }
}
Concrete class
[assembly: Dependency(typeof(PrismNinjectApp1.Application.DomainServices.UserService))]
namespace PrismNinjectApp1.Application.DomainServices
{
public class UserService : IUserService
{
public UserService() { }
}
}
View Model
namespace PrismNinjectApp1.ViewModels
{
public class MainPageViewModel : BindableBase, INavigationAware
{
private readonly IUserService _userService;
public MainPageViewModel()
{
_userService = DependencyService.Get<IUserService>();
}
//Implementation of INavigationAware interface (I'm using Prism)
}
}
But if I try do the same with generics I can't get the object instance:
Interface
namespace PrismNinjectApp1.test
{
public interface IMyInterface<T> where T : class { }
}
Concrete class
[assembly: Dependency(typeof(PrismNinjectApp1.test.MyInterface<>))]
namespace PrismNinjectApp1.test
{
public class MyInterface<T> : IMyInterface<T> where T : class { }
}
View Model
namespace PrismNinjectApp1.ViewModels
{
public class MainPageViewModel : BindableBase, INavigationAware
{
private readonly IMyInterface<Users> _myInterface;
public MainPageViewModel()
{
_myInterface = DependencyService.Get<IMyInterface<Users>>(); //Gets NULL value
}
//Implementation of INavigationAware interface (I'm using Prism)
}
}
Users class is a domain entity
public class Users
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[MaxLength(100)]
public string Name { get; set; }
}
Any idea how I can get this object instance?
I trying to do this because I want to use generics services and repositories with basic CRUD and search methods with this structure
App (project droid and ios)
Shared (portable project)
Application (for external services - portable projec)
Domain - (portable project)
Data - (portable project)
Xamarin Forms version: 2.3.4.247

Related

ASP.NET Core Web API : dependency injection based on runtime parameter value

I am working on an ASP.NET Core Web API application. My API will accept a country name as one of the input parameter from request body.
Due to nature of the application, we have country wise database with same schema. I have created DbContext for one of the databases and want to initialize the DbContext by the passing the connection string based on input request parameter value.
I have created factory method to return the needed database context based on the parameter passed to the factory method. However, the challenge I am facing is, while initializing the factory class as DI from controller, object of factory class is instantiated before the controller action is called. Hence, parameter value in factory method is empty.
How can I pass a parameter in runtime to initialize an object using dependency injection?
Here is the code...
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
public class MyDBContext : DbContext
{
public MyDBContext(DbContextOptions<MyDBContext> options)
: base(options)
{
}
public virtual DbSet<Student> Students { get; set; }
}
public interface IDbContextFactory
{
public MyDBContext GetDbContext(string
connectionString);
}
public class DbContextFactory : IDbContextFactory
{
public MyDBContext GetDbContext(string connectionString)
{
MyDBContext context = null;
if (!string.IsNullOrWhiteSpace(connectionString))
{
DbContextOptionsBuilder<MyDBContext> _dbContextOptionsBuilder = new DbContextOptionsBuilder<MyDBContext>().UseSqlServer(connectionString);
context = new MyDBContext(_dbContextOptionsBuilder.Options);
}
return context;
}
}
public interface IRepository
{
Student GetData();
}
public class Repository : IRepository
{
private MyDBContext _context;
public Repository(IDbContextFactory dbContextFactory)
{
// Here I need connection string based on input parameter (country) from request to dynamically generate country specific connection string
string connectionString = string.Empty;
_context = dbContextFactory.GetDbContext(connectionString);
}
public Student GetData()
{
return _context.Students.FirstOrDefault();
}
}
public interface IServiceAgent
{
Student GetData();
}
public class ServiceAgent : IServiceAgent
{
IRepository _repository;
public ServiceAgent(IRepository repository)
{
_repository = repository;
}
public Student GetData()
{
return _repository.GetData();
}
}
[ApiController]
[Route("[controller]")]
public class HomeController : ControllerBase
{
private readonly IServiceAgent _serviceAgent;
public HomeController(IServiceAgent serviceAgent)
{
_serviceAgent = serviceAgent;
}
[HttpGet]
public Student Get(string country)
{
return _serviceAgent.GetData();
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddScoped<IServiceAgent, ServiceAgent>();
services.AddScoped<IRepository, Repository>();
services.AddScoped<IDbContextFactory, DbContextFactory>();
services.AddScoped<DetermineCountryFilter>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}

Unable to resolve service for type with our own class

We are getting this exception when calling a web api controller:
InvalidOperationException: Unable to resolve service for type 'SDS.Lambda.Interfaces.ISecretManager' while attempting to activate 'SDS.Lambda.Controllers.SapController'.\r\n <p class="location">Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
StartUp.cs contains the following:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ISecretManager, SecretManager>();
}
The controller has this constructor:
public class SapController : Controller
{
public SapController(ISecretManager secretManager)
{
_secretManager = secretManager;
}
}
We have the same issue with other types being injected into the constructor, but the IConfiguration instance can be injected, for example that parameter does not cause an exception:
public SapController(IConfiguration configuration, ISecretManager secretManager)
The ISecretManager interface looks like this (yes, it really does):
namespace SDS.Lambda.Interfaces
{
public interface ISecretManager
{
}
}
And the class (yes, really - I reduced it down to avoid complexity):
namespace SDS.Lambda.Interfaces
{
public class SecretManager : ISecretManager
{
}
}
Are we providing the interface/concrete type incorrectly?
Is there a way to retrieve the concrete type to test whether it has been provided properly?
When execution reaches the bottom of ConfigureServices, if we look at the services instance result enumeration, in the debugger view, the types we are injecting are listed, so we can't see why they are failing to be instantiated.
UPDATE
To elaborate and explain the issue with another class/dependency in the same solution:
Controller:
namespace SDS.Lambda.Controllers
{
[Route("api/[controller]")]
public class SapController : Controller
{
readonly IHelper helper;
public SapController(IHelper helpme)
{
helper = helpme;
}
...
}
Interface:
namespace SDS.Lambda.Interfaces
{
public interface IHelper
{
}
}
Class:
namespace SDS.Lambda.Helpers
{
public class Helper : IHelper
{
public Helper()
{
}
}
}
StartUp:
namespace SDS.Lambda
{
public class Startup
{
public static IConfiguration Configuration { get; private set; }
private readonly AppSettings _appSettings;
public Startup(IConfiguration configuration)
{
Configuration = configuration;
_appSettings = configuration.GetSection("AppSettings").Get<AppSettings>();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(logger => logger.AddLambdaLogger());
services.AddSingleton<IHelper, Helper>();
services.AddControllers();
}
...
}

Com class not showing main interface

I have an interface and a class in the tyle ibrary that is produced the interface appears and so does the class but the class has no methods exposed on it. so I cannot create an Application object in say VBA in Microsoft Word and call the methods on it, does anyone know what is wrong?
[ComVisible(true), Guid("261D62BE-34A4-4E49-803E-CC3294613505")]
public interface IApplication
{
[DispId(207)]
[ComVisible(true)]
IExporter Exporter { get; }
[DispId(202)]
[ComVisible(true)]
object CreateEntity([In] kEntityType EntityType, [In] object aParent);
[DispId(208)]
[ComVisible(true)]
string GenerateSpoolFileSpec();
}
[ComVisible(true), Guid("BA7F4588-0B51-476B-A885-8E1436EA0768")]
public class Application : IApplication
{
protected Exporter FExporter;
public Application()
{
FExporter = new Exporter();
}
[DispId(207)]
[ComVisible(true)]
public IExporter Exporter
{
get {return FExporter;}
}
[DispId(202)]
[ComVisible(true)]
public object CreateEntity([In] kEntityType EntityType, [In] object aParent)
{
switch (EntityType)
{
case TypeJob:
return new Job(this, aParent);
case kappEntityType.kappEntityTypePage:
return new Page(this, aParent);
}
return null;
}
[DispId(208)]
[ComVisible(true)]
public string GenerateSpoolFileSpec()
{
string path = string.Format(JOB_PARAMS_PATH_SKELETON, SpoolFolder, DateTime.Now.ToString("yyyy.MM.dd.hh.mm.ss.fff"));
return path;
}
}
Got it, don’t let dotnet handle it for you on the interface put an interfacetype e.g.
[ComVisible(true), Guid("261D62BE-34A4-4E49-803E-CC3294613505"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
On the class use a classinterface e.g
[ComVisible(true), Guid("BA7F4588-0B51-476B-A885-8E1436EA0768"), ClassInterface(ClassInterfaceType.None)]

Service isn't implementing interface member noobie

I am re engineering an MVC3 app to take all linq out of controllers and in to proper layers.
I have got this as my structure SQL --> EF --> Repository --> Service --> Controller. I am using interfaces.
When compiling I am getting this error:
gpc.data.service.roleService does not implement interface member gpc.data.interfaces.iroleservice.HolderNamesbyRoleID(int).
I am totally new to proper architecture so apologies if this is blindingly obvious lol. Here is some code:
Repository:
namespace gpc.Data.Repositories
{
public class roleRepository :gpc.Data.Interfaces.IRoleRepository
{
private gpc.Models.gpcEntities _entities = new Models.gpcEntities();
public HolderNames HolderNamesbyRoleID(int roleid)
{
return (from i in _entities.HolderNames
where i.roleid == roleid select i).FirstOrDefault();
}
}
}
I then have an interface:
namespace gpc.Data.Interfaces
{
public interface IRoleRepository
{
HolderNames HolderNamesbyRoleID(int roleid);
}
}
Then I have the service:
namespace gpc.Data.Service
{
public class roleService : gpc.Data.Interfaces.IRoleService
{
private ModelStateDictionary _modelState;
private gpc.Data.Interfaces.IRoleRepository _repository;
public roleService(ModelStateDictionary modelState)
{
_modelState = modelState;
_repository = new gpc.Data.Repositories.roleRepository();
}
public roleService(ModelStateDictionary modelState,
gpc.Data.Repositories.roleRepository repository)
{
_modelState = modelState;
_repository = repository;
}
public HolderNames HolderNames(int roleid)
{
return _repository.HolderNamesbyRoleID(roleid);
}
}
}
I then have another interface:
namespace gpc.Data.Interfaces
{
public interface IRoleService
{
HolderNames HolderNamesbyRoleID(int roleid);
}
}
I created a very simple ienumerable in this structure and I was able to get data on to the view through the controller as i would expect. I guess that as this one is a bit more complicated that a select everything and throw it at a view I must have missed something. I don't know if it makes a difference, but "holdernames" is a SQL view as opposed to a table.
Any help greatly appreciated
It's basically just what your compiler error shows. Your IRoleService interface defines a method named HolderNamesbyRoleID, but in your implementation you only have a method named HolderNames.
I assume this is just a mistype on your part.
Interface only contains the signature. You have to write actual implementation in class where you have implemented your interface. In your case you have define method HolderNamesbyRoleID in IRoleRepository but you have not implemented this method in roleService class. You must have to implement HolderNamesbyRoleID in roleService class.
Your roleService class code becomes like below.
namespace gpc.Data.Service
{
public class roleService : gpc.Data.Interfaces.IRoleService
{
private ModelStateDictionary _modelState;
private gpc.Data.Interfaces.IRoleRepository _repository;
public roleService(ModelStateDictionary modelState)
{
_modelState = modelState;
_repository = new gpc.Data.Repositories.roleRepository();
}
public roleService(ModelStateDictionary modelState,
gpc.Data.Repositories.roleRepository repository)
{
_modelState = modelState;
_repository = repository;
}
public HolderNames HolderNamesbyRoleID(int roleid)
{
return _repository.HolderNamesbyRoleID(roleid);
}
}
}
Refer interface for more info.

Passing multiple models to a view using MVC3 and Ninject

I'm new to MVC3 (which is why I bought a book on it, which is why I now have this question!), so apologies if there is an obvious answer to this!
I'm following a simple example of building a shopping cart in MVC3. The book advocates the use of Ninject for dependency injection, which I'm also new to. It all seems straight forward enough with one model, in this case Product, but building upon this I am struggling to add a second model and display this in the same view where the Product model is displayed. I've tried using a View Model but all examples I find wrap several classes into one model and I can't quite figure out how to implement this in my code.
The class:
public class Product
{
public int ProductId {get;set;}
public string Name {get;set;}
}
Abstract Repository:
public interface IProductRepository
{
IQueryable<Product> Products {get;}
}
Class to associate model with database:
public class EFDbContext : DbContext
{
public DbSet<Product> Products {get;set;}
}
Product Repository which implements abstract interface:
public class EFProductRepository : IProductRepository
{
private EFDbContext context = new EFDbContext();
public IQueryable<Product> Products
{
get {return context.Products;}
}
}
Ninject binds IProductRepository to EFProductRepository in a ControllerFactory class.
Controller:
public class ProductController : Controller
{
private IProductRepository repository;
public ProductController(IProductRepository productRepository)
{
repository = productRepository;
}
public ViewResult List()
{
return View(repository.Products);
}
}
My problem is passing repository.Products to the strongly typed view; if I need to pass another entity, which is very feasible how would I achieve this???
You can build a ViewModel which looks like the following:
public class YourViewModel
{
public List<Product> Products { get; set; }
public List<OtherEntity> OtherEntities { get; set; }
}
Then you can wrap the repository in a service which contains all the methods
you need to fulfill your requests and/or businesslogic:
public class YourService
{
private IProductRepository repository;
public List<Product> GetAllProducts( )
{
return this.repository.Products.ToList( );
}
public List<OtherEntity> GetAllOtherEntites( )
{
return this.repository.OtherEntites.ToList( );
}
}
and finally in the Controller you fill the ViewModel appropriately
public class ProductController : Controller
{
private YourControllerService service = new YourControllerService( );
// you can make also an IService interface like you did with
// the repository
public ProductController(YourControllerService yourService)
{
service = yourService;
}
public ViewResult List()
{
var viewModel = new YourViewModel( );
viewModel.Products = service.GetAllProducts( );
viewModel.OtherEntities = service.GetAllOtherEntities( );
return View( viewModel );
}
}
Now you have multiple entities on you ViewModel.
Maybe it is not directly answer to your question but it is connected.
If you correctly pass the model to view, you can handle it like this
#model SolutionName.WebUI.Models.YourViewModel
#Model.Product[index].ProductId
#Model.OtherEntity[index].OtherId
I know that it's old post but it maybe help others :)

Resources