I have a few question related to Xamarin Prism dependency, could you please help me?
In the App.xmal.cs I've registered a service called UserService
protected override void RegisterTypes()
{
Container.RegisterType<IUserService, UserService>(); ....
And this works perfectly via ViewModels as in numerous examples on the Internet.
But in my UC on application load I need to call a method from UserService to check some login details.
At the moment on OnInitialized I redirect a user to some dummy page in order to use dependency instanced UserService.
Is it possible to get an instance of UserService directly in the App.xaml.cs via Prism dependency injection (outside of a model)
Rather easy:
Container.Resolve<IUserservice>();
...not before the registration, of course...
...and not nice, too, try not to use the container directly, but in this case, it's your only option.
Related
Trying to use Prism 8, ContainerLocator, IHttpClientFactory and Platform-Specific Service registration with DryIoc Extensions (not Magician) in a Xamarin Forms application
I have these nuget packages installed
Prism.DryIoc.Extensions
Prism.Forms
My main Xamarin Application inherits from PrismApplicationBase.
In platform code (eg Android) I have IPlatformInitializer implented by MainActivity and for platform-specific services I use:
LoadApplication(new App(this));
as documented here:
https://prismlibrary.com/docs/dependency-injection/platform-specific-services.html
This line causes the IContainerExtension to be resolved in the shared code
protected override IContainerExtension CreateContainerExtension()
...but I can't find a way to successfully return a valid IContainerExtension implementation.
I've attempted:
https://prismlibrary.com/docs/dependency-injection/container-locator.html
var createContainerExtension = () => new DryIocContainerExtension();
ContainerLocator.SetContainerExtension(createContainerExtension);
But the code given here can't even compile - the DryIocContainerExtension class created is defined INTERNAL and isn't available to my application code.
If I use...
PrismContainerExtension.Init();
or
return ContainerLocator.Current;
...as worked previously (eg Prism 7.2) I get a runtime error as described here:
https://githubmemory.com/repo/dansiegel/Prism.Container.Extensions/issues/180
ValueFactory attempted to access the Value property of this instance.
Please can someone advise what I'm doing wrong, or do I have to get my company to pay for Magician to resolve my issue?
I am using Xamarin Forms. I would like to download jpg file (it is done) and then open that jpg in default application on Android/iOS (opening photo browser with this photo). Of course photo is single example, I would like to open any file in default application.
I found several solutions native-only but my application is designed to be cross-platform. I though that I can use Launcher from Xamarin.Essentials package but apparently I can't.
How to achieve this?
You can have a try with Xamarin.Essentials: Launcher:
var fn = "File.txt";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllText(file, "Hello World");
await Launcher.OpenAsync(new OpenFileRequest
{
File = new ReadOnlyFile(file)
});
I found several solutions native-only
Opening something in another app is quite close to the system for a mobile application and there are some things to consider, which dependend on the platform. Usually, mobile apps run in a sandbox with very limited access to the surrounding system. Particularly this means that, if you downloaded a file to the sandbox of your app, other apps (which native viewers are), aren't allowed to access the file.
On Android, you can copy the file to a shared space (see Application.Context.GetExternalFilesDir(null)) and then open it. This might be possible with Essentials, but I'm not quite sure, but since we're on the Android platform anyway now, you could create an intent now anyway.
On iOS you create controllers from within your app (for example the QLPreviewController to preview the file) that may access items in your sandbox. Depending on the type of controller (e.g. UIActivityViewController) they may open other apps.
How to use this platform-independently?
Since you are programming a platform independent app, you'll have to take care that the correct class is called to the platform dependent work. There are several options how you can achieve this
Use the DependencyService
Use a real dependency injection framework
Use an abstract base class with initialization in the platform dependent projects
DependencyService
To use the Xamarin.Forms DependencyService you need two things
An interface for the functionality you'd like to implement
One implementation per platform
Assuming you hvae a simple interface to share a file
public IShareFile
{
void ShareFile(string fileName);
}
you can implement an implementation of this interface on each platform and add the DependencyAttribute to the assembly. e.g. for iOS:
[assembly: Dependency(typeof(MyApp.iOS.DeviceOrientationService))]
namespace MyApp.iOS
{
public class ShareFile : IShareFile
{
public void Share(string fileName)
{
// implementation goes here
}
}
}
The general scaffold is the same for Android, albeit the implementation differs.
Using a real dependency injection framework
Basically it's pretty much the same. You can skip the DependencyAttribute, though. In order to make the implementation available you'll have to get hold of the DI container from your platform specific code, which might be tricky. This might be an overshoot for a single dependency, but if you're using a DI container anyway and there are X dependencies, it might be worth the effort.
Using an abstract base class
Add an abstract base class to your project
public abstract class ShareFile
{
public static ShareFile Instance { get; protected set; }
public abstract void Share(string fileName);
}
and in your implementation in the platform specific project, you add an Init() method
internal class ShareFileImpl : ShareFile
{
public static void Init()
{
ShareFile.Instance = new ShareFileImpl();
}
public void Share(string fileName)
{
// implementation goes here
}
}
This init method must be called from your platform specific code. Most likely during initialization. The implementation can then be accessed via its abstraction from your platform independent code (of course you'll see only the abstraction, public methods added to ShareFileImpl won't be visible from your platform independent code).
ShareFile.Instance.Share(fileName);
A combination of the abstract class approach and dependency injection is also conceivable. When registering your classes in the DI framework, you could register the platform instance like
container.RegisterInstance<ShareFile>(ShareFile.Instance);
This way you can make use of the DI container features (e.g. constructor injection), while keeping the hassles of using the DI container from your platform specific project away from you. The drawback is, that you'll still have to call ShareFileImpl.Init() from your platform specfic code.
I have a fair idea of using the Repository Pattern and have been attempting to "upgrade" our current way of creating ASP .Net websites. So i do the following
Create a solution with a class project called DataAccessLayer and another class project called BusinessLogicLayer. Finally a 3rd project which is my ASP .Net website (a normal site).
I add a dbml file to the DAL and drag a table, then in my BLL i add an interface and a class which implements this interface:
My interface
namespace BLL.Interfaces
{
interface IUser
{
List<User> GetAllUsers();
}
}
In my class
namespace BLL.Services
{
public class UserService : BLL.Interfaces.IUser
{
public List<User> GetUsers()
{
throw new NotImplementedException();
}
}
}
I know the code is not fully completed, but there for illustrative purposes.
So i right click the BLL project > Manage NuGet Packages > Searched for Ninject and found a few. I was overwhelmed with the number of entries returned after after further research i am lost in how to add Ninject to a normal ASP .Net website? Specifically which addin i require? As there are many MVC and reading further i think im a little confused.
I was trying to add it to the BLL project as thats where i THINK it should go so i can register my services in there.
Could anyone guide me in what i need to so in order to use Ninject entries but im not using MVC?
Install Ninject.Web either from "Package Manager Console" or NuGet.
Version is 3.2.1 as of this writing.
OR
It will install the following 4 packages -
Sample Service Class
public interface IUserService
{
List<string> GetUsers();
}
public class UserService : IUserService
{
public List<string> GetUsers()
{
return new List<string> {"john", "eric"};
}
}
Then add binding to ~/App_Start/NinjectWebCommon.cs.
In code behind page, property inject using [Inject] attribute.
In Addition in answer by win I would advise people not to get confused by using Constructor based injection in ASP.NET Webforms as Web Forms doesn't support constructor based injection simply. In default configuration they only support Property based Injections as already demonstrated by Win.
When using Unity 2.0 for dependency injection within a web application, it appears that user controls, pages, etc will all need make explicit calls to retrieve the container and "fetch" the dependencies … so using the annotations like [dependency] won't offer any value. This is likely since the location of the container (application context, http context cache, etc.) is unknown in the web configuration.
Since Unity itself provides method interception, isn't there a way to "tell" unity how to fetch the container correctly when you build your own web application? Rather than having to create base classes for page, etc.?
The problem is that the WebForms Pages and Controls are not set up to allow for construction by dependency injection, so Unity never gets invoked at all unless the class invokes Unity itself. I've found the best pattern in these cases is to invoke the DI framework in the constructor via a Service Locator and then use annotations to mark dependency properties. Something like this:
public MyPage()
{
// Injector is a wrapper class so you can change the underlying DI framework
// later if necessary.
Injector.Inject(this);
}
[Dependency]
public SomeService MyService {get;set;}
I've been using the Ninject.Web extension to inject business objects, repositories, Entity Framework context etc into my application. This works very well using the [Inject] attribute which can be applied within a webform that inherits from PageBase. I am now running into a snag as I am trying to write a custom membership provider that needs injection done inside of it but of course this provider is not instantiated from within a webform. Forms Authentication will instantiate the object when it needs it. I am unsure how to about doing this without having access to the [Inject] attribute. I understand that there is an application level kernel somewhere, but I have no idea how to tap into it. Any suggestions would be greatly appreciated.
You don't have to use the service locator pattern, just inject into properties of your custom membership provider in Application_Start. Assuming you've registed the providers properly you can do this with something like:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
// Inject account repository into our custom membership & role providers.
_kernel.Inject(Membership.Provider);
// Register the Object Id binder.
ModelBinders.Binders.Add(typeof(ObjectId), new ObjectIdModelBinder());
}
I've written up a more in depth explanation here:
http://www.danharman.net/2011/06/23/asp-net-mvc-3-custom-membership-provider-with-repository-injection/
You do a IKernel.Inject on the the instance. Have a look at the source for the Application class in the extension project you're using.
In the case of V2, it's in a KernelContainer. So you need to do a:
KernelContainer.Inject( this )
where this is the non-page, non application class of which you speak.
You'll need to make sure this only happens once - be careful doing this in Global, which may get instantiated multiple times.
Also, your Application / Global class needs to derive from NinjectHttpAppplication, but I'm sure you've that covered.
you may need to use the Service Locator pattern, since you have no control over the creation of the membership provider.