Prism Xamarin Forms - using shared service in shared service - xamarin.forms

Hy i wrote a couple of shared services in my prism application.
I´m now at the point where i want to chain my servces. I want to use the services in another service. For example i want to use mit Loggerservice to log errors not only in my ViewModel, but also in the other Services.
Is that possible in a better way than i do now?
Now i´m requesting both services in my ViewModels constructor.
Than i call a method of service one and give them a reference to the service two as a parameter.
I think there is a better way of doing this in Prism?!
Thanks

In general yes you can register and reuse services within other services. For example you could have:
public interface ILogger
{
void Log(string message);
}
public interface IApiService
{
Task DoStuff();
}
public class ApiService : IApiService
{
ILogger _logger { get; }
public ApiService(ILogger logger)
{
_logger = logger
}
public Task DoStuff()
{
// Do DoStuff
_logger.Log("Some Message");
}
}
You however should not attempt to use INavigationService within your services as the NavigationService requires an understanding of which Page you are navigating from to work correctly.

Related

How do I inject a DBContext into a service in Startup?

I have a service that I want to use in a .Net core Blazor app.
The service uses a context that I want to pass to it.
public class MyService
{
public AddDbContextContext { get; set; }
public MyService(AddDbContext mycontext)
{
Context = mycontext;
}
}
In Startup, I create the context that I want the service to use:
public void ConfigureServices(IServiceCollection services)
{
//configure the context
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("HIDDEN"));
//how do I pass the context?
services.AddSingleton<MyService>();
}
How do I pass the context to service?
How do I pass the context to service?
You don't pass the context to the service. It is automatically done when the DI container creates your service.
Since your DBContext is named ApplicationDbContext, your service should look like this:
public class MyService
{
private ApplicationDbContext _context;
public MyService(ApplicationDbContext context)
{
_context = context;
}
}
Note: You can only use DBContext in Blazor Server App
Note: I've only answered your question here. But it's very likely you'll have issues with the DBContext, depending on what you do in your service. You should consult the documents how to use the DBContext in Blazor, particularly, why and how you should use AddDbContextFactory

Unit of work pattern not allowing me to create db context without options

I am using ef core and I am trying to implement the repository pattern as part of best practices. But I am we bit confused on the context normally I would create the context in the and inject
HomeController(WarehouseDBContext _context)
I have created my unitOfWork Class as suggested by the docs here
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application#creating-the-unit-of-work-class
However I am tad confused. It's expecting options here which is normally handled on the controller.
My UnitOfWork class
public class WarehouseUnitOfWork : IDisposable
{
private WarehouseDBContext context = new WarehouseDBContext();
private WarehouseRepository<StockItem> stockRepository;
public WarehouseRepository<StockItem> StockRepoistry
{
get
{
if (this.stockRepository == null)
{
this.stockRepository = new WarehouseRepository<StockItem>(context);
}
return stockRepository;
}
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
But here it is complain that it expect options which would I presume contain the connection string. I am trying to decouple my code from EF so that If I want to upgrade in the future will be easier. My WareshouseDBContext is describe below
As you can see it is expecting options. What should I pass through here?
namespace WareHouseDal.Dal {
public class WarehouseDBContext : IdentityDbContext<ApplicationUser> {
public WarehouseDBContext(DbContextOptions<WarehouseDBContext> options)
: base(options) {
}
public DbSet<WarehouseCrm> Warehouse { get; set; }
public DbSet<Company> Companies { get; set; }
}
}
When I used to create my context before I just used the singleton pattern of
private readonly WarehouseDBContext _context;
Is their something else I need to do to allow it to accept the creation of the context on the unit of work level.
Error being given is
You shouldn't create a DbContext manually. Why not injecting the DbContext in your UOW class? Then the DI will manage the life cycle of the db context. To be honest I am not a fan of adding a UOW wrapper around EF which already implements the UOW pattern.
I would recommend you to see both talks, it will change the way you structure apps forever:
https://www.youtube.com/watch?v=5OtUm1BLmG0&ab_channel=NDCConferences
https://www.youtube.com/watch?v=5kOzZz2vj2o&t=3s&ab_channel=NDCConferences
Another amazing talk about EF Core details: https://www.youtube.com/watch?v=zySHbwl5IeU&ab_channel=NDCConferences
If you want to stick with Repository pattern, please check Ardalis repository with a clear example: https://github.com/ardalis/CleanArchitecture
I agree Ardalis repository is a great tutorial/example, in case if anyone want a lite solution to implement the Repository and Unit of Work Patterns in EF 5/EF 6.
you may check out the below one, I tested it would work in EF Core 6
https://pradeepl.com/blog/repository-and-unit-of-work-pattern-asp-net-core-3-1/

Asp.net core, basic problems i dont understand

First Problem:
services.AddMemoryCache(); // in Startup config
public class AController
{
public AController(IMemoryCache cacheA) { }
}
public class BController
{
public BController(IMemoryCache cacheB) { }
}
problem is that cacheA is the same as cacheB
i'd like to have private API (cluster connections) and public API (exposed to frontend)
how to separate them while keeping it all DI pattern friendly?
Second problem;
i want to have a service that requests some external webserver via HTTP
and its results would be cached in that service, also stored in DB
so we first query localCache then query DB then query external server
results from that service would be used in Controllers and sent to frontend
How to implement such thing with all the fancy asp.netcore patterns?
cache must be the ONE(singleton) so we dont waste DB requests
? adding such Service as services.SCOPED<> but then how to keep it its cache same for every instance (some singleton DI? or static MemoryCache instance?)
i have no idea, no damn idea begging for help
in node.js i would have done it all in a couple of minutes, but its Microsoft hey
Define two cache interfaces:
public interface IPrivateMemoryCache: IMemoryCache
{
}
public interface IPublicMemoryCache: IMemoryCache
{
}
public class AController
{
public AController(IPrivateMemoryCache cacheA) { }
}
public class BController
{
public BController(IPublicMemoryCache cacheB) { }
}
Now you can define different instantiation rules for your IoC container.

Where to do DBContext.SaveChanges() if I'm using InRequestScope()

I'm developing an ASP.NET MVC 5 Web API application with C#, .NET Framework 4.5.1, Entity Framework 6.1.1 and the latest version of Ninject (I have also installed Ninject.MVC5).
I'm learning how to implement dependency injection, and I think I have learned it, but I have a question. These are my interfaces and classes.
Unit of work interface:
public interface IUnitOfWork
{
void Commit();
}
Custom DbContext implementation (I use IUnitOfWork interface to allow DI):
public class EFDbContext : DbContext, IUnitOfWork
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
[ ... ]
}
public void Commit()
{
this.SaveChanges();
}
}
And this is how allow Dependency Injection with Ninject and Ninject.Web.Common.
I have a class, NinjectConfigurator, that adds bindings:
public class NinjectConfigurator
{
public void Configure(IKernel container)
{
// Add all bindings/dependencies
AddBindings(container);
// Use the container and our NinjectDependencyResolver as
// application's resolver
var resolver = new NinjectDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
private void AddBindings(IKernel container)
{
ConfigureLog4net(container);
container.Bind<IUnitOfWork>().To<EFDbContext>().InRequestScope();
container.Bind<IGenericRepository<User>>().To<GenericRepository<User>>();
}
private void ConfigureLog4net(IKernel container)
{
log4net.Config.XmlConfigurator.Configure();
var loggerForWebSite = LogManager.GetLogger("MattSocialNetworkWebApi");
container.Bind<ILog>().ToConstant(loggerForWebSite);
}
}
And finally, I have this on NinjectWebCommon:
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
var containerConfigurator = new NinjectConfigurator();
containerConfigurator.Configure(kernel);
}
I use .InRequestScope() because I want a EFDbContext instance per request.
My question is: When do I have to do EFDbContext.SaveChanges()? If I'm using one instance per request I think I have to save the changes at the end of the request, isn't it?
Where do I have to put EFDbContext.Commit()?
The way I do it, and have seen done other places, is to either commit in your business layer, or in your controller, after each transaction. That means sometimes SaveChanges() will be called more than once per request, but that shouldn't be a significant problem.
I've learned a lot from looking at the code for SocialGoal, which can be found here. It uses Autofac for DI, but it's the same principles as your own code. Maybe you can get some inspiration and answers there too.

Creating a Unity DependencyResolver for SignalR

I'm using SignalR 0.5.2 and I'm trying to get a DependencyResolver set up using Unity. I've written the simplest code I can. I have a hub that I'm trying to inject into which looks like this:
public class SimpleHub : Hub
{
private readonly ITestService _service;
public SimpleHub(ITestService service)
{
_service = service;
}
public void Update()
{
Clients.callback("Kevin");
}
}
and a DependencyResolver that looks like this:
public class UnityDependencyResolver : DefaultDependencyResolver
{
private readonly IUnityContainer _container;
public UnityDependencyResolver(IUnityContainer container)
{
_container = container;
}
public override object GetService(Type serviceType)
{
if (_container.IsRegistered(serviceType))
{
return _container.Resolve(serviceType);
}
return base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
if (_container.IsRegistered(serviceType))
{
return _container.ResolveAll(serviceType);
}
return base.GetServices(serviceType);
}
}
I register the dependency resolver in Global.asax
protected void Application_Start()
{
IUnityContainer container = new UnityContainer();
InitializeContainer(container);
SignalR.IDependencyResolver resolver = new UnityDependencyResolver(container);
GlobalHost.DependencyResolver = resolver;
RouteTable.Routes.MapHubs();
// more MVC stuff here
}
where InitializeContainer register the ITestService in Unity
The resolver "works" in that it's getting called for all the SignalR types, and if I leave my hub with a default constructor it all gets loaded. However the resolver never gets asked to resolve the ITestService interface.
I've also tried passing the resolver to MapHubs, still no luck. I've also tried property injection using the [Dependency] attribute and that didn't work either.
Do I need to register the resolver with MVC as well? (I have tried that by implementing both IDependecyResolver interfaces but get an exception telling me the resolver doesn't implement IServiceLocator)
So I've sort of fixed this. I wondered if the fact that the Hub was registered with the signalr container and the interface was registered with the Unity container was causing the issue. So I registered the Hub with Unity and then everything works.
This sort of makes sense as there are two containers.
Is this the standard behaviour?
In case someone else is wondering... I found a good SPA example that uses
SignalR 1.0.1
Unity 3
A bunch of other frameworks
The interesting thing is the way he create the container, the dependencies and everything else. Worth checking it out.

Resources