I have a Portable class library which I am going to use for Windows 8 and phone apps. So I created a common viewmodeland, and now I want to handle storage functionality in viewmodels. I found a PCLStorage package which is used to deal with this scenario.
I have a code like this on Windows 8 and now I want to write this in PCL using PCLStorage.
public static object LoadSettings(string key)
{
if (Windows.Storage.ApplicationData.Current.LocalSettings.Values.ContainsKey(key))
{
if (Windows.Storage.ApplicationData.Current.LocalSettings.Values[key] != null)
{
return Windows.Storage.ApplicationData.Current.LocalSettings.Values[key];
}
else
{
return null;
}
}
else
{
return null;
}
}
I found a way, I have created a interface for Storage used in viewmodel. And have created a class to handle storage for phone and metro in respective projects. When I am creating a object of MainViewModel I am passing storage object also.
So I want to know, is this right?
I believe the simplest pattern would be to Register the current-platform-defendant-implementation within the container bootstrapper on the 'specific' 'shell' for platform and get the dependenciy in the constructor
Or simply skip the IoC thing and instantiate stuff manually
using MyInfrastructureAssembly.Interfaces;
public MyApp: App // MyNewPlatFormApp
{
public override Initiaze()
{
var bootsrapper = new Boostrapper(MyIoC.Current);
}
}
public class Bootsrapper: TheBootStrapperOfMyIoc
{
public Bootsrapper(IocContainer container)
{
Container = container;
}
public override Register()
{
Container.Register<IMyAbstractedService,MyPlatformDependantService>();
}
}
MyPlatformDependantService : IMyAbstractedService
{
public object Get(); // IMyAbstractedService.Get()
}
public class MyViewModel:ViewModelBase
{
IMyService MyService {get;set;}
MyViewModel(IMyAbstractedService myServcice)
{
MyService = myService;
}
public object Thing // LazyThing provided by IMyAbstractedService
{
get
{
if(_thing!=null)
return _thing;
return _thing = GetIt();
}
set
{
if(Equals(value,_thing)) return;
_thing = value;
base.NotifyMagicalChanges()
}
}
public void GetIt()
{
MyServcie.Get();
}
}
Static Version : Runs on LinqPad
enter code here
private async void CheckIfExist()
{
try
{
var isoStore = FileSystem.Current.LocalStorage;
var folder = await isoStore.CreateFolderAsync("xxx",
CreationCollisionOption.ReplaceExisting);
ExistenceCheckResult result = await isoStore.CheckExistsAsync("xxx");
switch (result)
{
case (ExistenceCheckResult.FolderExists):
Console.WriteLine(":)"); break;
case (ExistenceCheckResult.NotFound):
Console.WriteLine(":("); break;
}
}
catch (Exception)
{
Console.WriteLine(":<");
}
}'
I found a way, I have created a interface for Storage used in viewmodel. And have created a class to handle storage for phone and metro in respective projects. When I am creating a object of MainViewModel I am passing storage object also. So i want to know that Is this right?
Yes, this is a good solution. Dan's answer is basically just the same thing but using an IoC container.
You can also try the Xam.Plugins.Settings library, which basically does for settings what PCL Storage does for File IO.
Related
I am trying to learn dependency inversion and IOC. In the process, I have hit a wall.
This is what I understand about DI principle -> high-level classes are based on abstractions and not implementations.
All good.
So keeping the above in mind. I have the following example.
public interface IServiceA
{
public void DoSomething();
}
public class ServiceA : IServiceAInterface
{
IDataInterface dataSource;
DataSourceType data;
// omitted config injectino for brevity
public ServiceA(IDataInterface _data)
{
dataSource = _dataSource;
var dataSourceName = config.GetValue<string>("DataSourceName");
data = dataSource.GetDataSource(dataSourceName);
}
public void doSomething()
{
data.doSomething();
}
}
public interface IDataInterface
{
public DataSourceType getDataSource(string ds);
}
public class DataAccessService : IDataInterface
{
public DataSourceType GetDataSource(string dataSource)
{
if (dataSource == "InApp")
{
var source = new DataSourceType();
return source;
}
else
{
return null;
}
}
}
The above is a service class which needs data to perform tasks which it gets from DataAccessService.
Now I am using an application class/model for persistence throughout the app lifetime. Therefore I have registered it as a singleton.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
---
services.AddSingelton<IDataInterface,DataAccessService>();
service.AddScoped<IServieAInterface,ServiceA>();
---
}
This does not work.
I hypothesize it is because, the parent service (service A) has a lesser lifetime than the child service (DataAccessService).
I have understood through this that service A is responsible for instantiation of the object.
However, I expected the IOC container to instantiate only one DataAccessService object and inject it to all services that need this.
Not sure why my assumption is wrong.
Based on the above hypothesis I tried the following:
public interface IDataInterface
{
}
public class DataAccessService : IDataInterface
{
public DataSourceType dataSource;
public DataAccessService(string ds)
{
if (ds == "InApp")
{
this.dataSource = new DataSourceType();
}
else
{
this.dataSource = null;
}
}
}
public class ServiceA: DataAccessService,IServceAInterface
{
DatSourceTye data;
public ServiceA():base("InApp")
{
config = _config;
data = dataSource;
}
public void doSomething()
{
data.doSomething();
}
}
Startup.cs
// Hoping to pass parameter through startup
services.AddSingleton<IDataInterface>(x =>
ActivatorUtilities.CreateInstance<DataAccessService>(x, "InApp")
);
service.AddScoped<IServieAInterface,ServiceA>();
I hoped the above would work, as here the DataAccessService is responsible for initialization.
But still a new DataAccessService object is created for every class.
I think, I have messed up my understanding about how the life times work.
need help on this.
Also, what I am trying to achieve is a singleton data source on which different services act on throughout the application lifetime.
Transient and scoped services consuming a singleton data source. I think this should be possible
Is there something bad in terms of design in what I am trying to achieve?
public DataAccessService(string ds)
{
if (ds == "InApp")
{
this.dataSource = new DataSourceType();
}
else
{
this.dataSource = null;
}
}
This method in the data service was being called every time, I needed the data source.
As this method is instantiating another class manually, though the service is singleton,
every time the above method - DataAccessService was called , I was getting a new instance.
I have a Web project and a Windows Service project in my solution. I have created 2 different binding modules for these 2 projects, but as you can see it has a lot of duplicate code... the only difference is that I am using InRequestScope() for the Web project and InTransientScope() for Windows Service project.
Is it possible combine the bindings, and add the scope depending on the project/entry point?
public class WebModule : NinjectModule
{
public override void Load()
{
Bind<ApplicationDbContext>().ToSelf().InRequestScope();
Bind<IMyRepository>().To<MyRepository>().InRequestScope();
// more types ... InRequetScope();
}
}
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<ApplicationDbContext>().ToSelf().InTransientScope();
Bind<IMyRepository>().To<MyRepository>().InTransientScope();
// more types ... InTransientScope();
}
}
Update:
As explained by ninject team, we can use InRequestScope() in both scenarios... since there is no concept of Request in a Windows Service project, ninject would use the default scope, which is InTransientScope() in the service project.
Original Answer
The best solution that I have come up with is to create an extension method:
public static class NinjectExtensions
{
public static IBindingNamedWithOrOnSyntax<T> GetScopeByName<T>(this IBindingInSyntax<T> syntax, string scope)
{
if (scope.Equals("request", StringComparison.InvariantCultureIgnoreCase))
{
return syntax.InRequestScope();
}
else if (scope.Equals("thread", StringComparison.InvariantCultureIgnoreCase))
{
return syntax.InThreadScope();
}
else if (scope.Equals("singleton", StringComparison.InvariantCultureIgnoreCase))
{
return syntax.InSingletonScope();
}
return syntax.InTransientScope();
}
}
And set the scope dynamically.
public class MyModule : NinjectModule
{
private string _scope = "transient";
public MyModule()
{
if (Convert.ToBoolean(ConfigurationManager.AppSettings["IsWebProject"]))
{
_scope = "request";
}
}
public override void Load()
{
Bind<ApplicationDbContext>().ToSelf().GetScopeByName(_scope);
Bind<IMyRepository>().To<MyRepository>().GetScopeByName(_scope);
// more types ... InRequetScope();
}
}
Note: I am not sure if there is a better solution... this is just the cleanest approach that has come to my mind.
Been googling it for a while, but found nothing really good.
So, the thing is, in MVVM Cross guides our solution (for mobile platforms) is separated on, as example, HelloWorld.Core project and few platform specific projects, as example HelloWorld.Android.UI.
You can see full tutorial here https://www.mvvmcross.com/documentation/tipcalc-tutorial/the-tip-calc-tutorial
And, the thing is, in our .Core project we creating Services, ViewModels and we registering it in MVVM Cross provided IoC-container.
In example which provided by the MvvmCross documentation Service implementation is really simple, just one function like that
public class CalculationService: ICalculationService
{
public double TipAmount(double subTotal, int generosity)
{
return subTotal * ((double)generosity)/100.0;
}
}
so we just go ahead, registering it in our App.cs and then its fine to use in binded ViewModel
public class App: MvxApplication
{
public App()
{
Mvx.RegisterType<ICalculationService, CalculationService>();
Mvx.RegisterSingleton<IMvxAppStart>(new MvxAppStart<HomeViewModel>());
}
}
View model code :
public class TipViewModel : MvxViewModel
{
readonly ICalculation _calculation;
public TipViewModel(ICalculation calculation)
{
_calculation = calculation;
}
// ...
double _tip;
public double Tip
{
get {
return _tip;
}
set
{
_tip = value;
RaisePropertyChanged(() => Tip);
}
}
void Recalculate()
{
Tip = _calculation.TipAmount(SubTotal, Generosity);
}
}
But the thing is, when I started playing around with that, I decided, to, let say, code some simple local storage data scanner to find some specific files.
Simple code example:
public class SimpleDataScanner : IBaseDataScanner
{
private string _basePath { get; set; }
private List<string> _scanResult { get; set; }
public SimpleDataScanner()
{
_basePath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
_scanResult = new List<string>();
}
public List<string> BasicDataScan(string startPath = null)
{
string startFolder = _basePath;
if (startPath.Length > 0 && startPath.Length != null)
{
startFolder = Path.Combine(_basePath, startPath);
}
try
{
TreeScan(startFolder);
}
catch (Exception)
{
throw;
}
return _scanResult;
}
private void TreeScan(string path)
{
foreach (var file in Directory.GetFiles(path))
{
if (Path.HasExtension("pdf"))
{
_scanResult.Add(file);
}
}
foreach (string dir in Directory.GetDirectories(path))
{
TreeScan(dir);
}
}
}
And, as I found out, the problems are:
1) I can't use Android specific functions and properties in PCL
2) I can't use reference in my PCL Core project to, lets say, some other Android class lib project
So, I can't create working Service which means I can't register it in IoC-container and pass to ViewModel.
Whats the way of doing such things?
Any tutorials? Or I getting whole idea wrong?
You need to implement the interface in your platform code, and register the concrete implementation against the interface in Setup.cs inside your platform project. So in your case, IDataScanner would exist inside your Core project, while SimpleDataScanner would live in the Android project.
Inside Setup.cs, you'd register the concrete implementation like this:
protected override void InitializeFirstChance()
{
base.InitializeFirstChance();
Mvx.RegisterSingleton<IDataScanner>(() => new SimpleDataScanner());
}
Essentially, if the interface requires platform-specific or full .NET framework code to implement, those per-platform implementations live in the platforms and are registered in the platform setup. If both the interface and the implementation are shared within the Core project, the dependency can be registered in App.cs.
I have been having a play with prism and decided to convert an application to a modular prism application using Prism + WPf + Unity.
This application talks to various bits of hardware so the first thing was to put all my hardware classes into separate modules.
Taking my camera class as an example which talks to a camera system via Ethernet.
Lets say my camera class is like this (before PRISM conversion)
Public Class Camera
{
// bunch of properties
public Task<bool> TakePhoto()
{
return Task.Run(()=>
{
// ...
// Do taking photo stuff
// ...
return CameraPhotoTakenResult; // Return result of taking photo
});
}
}
Before PRISM conversion I call the TakePhoto method like so
var TakePhoto = MyCamera.TakePhoto();
// ...
// Do some stuff and call other methods
// ...
var result = await TakePhoto;
// Check the result and do something with it
// ...
// Continue doing other stuff
From my understanding, I now have to use the EventAggregator to trigger the camera, which is fine, but would this mean I would have to use another Event to send back the result? if so then how can I modify my code to await on this?
You can use the type as normal. Break out the public interface of the class into a common project which both your hardware module and consumer will reference. Your hardware module registers a class in some kind of Dependency Injection container (my example will use Unity):
public class HardwareModule : IModule
{
IUnityContainer _container;
public HardwareModule(IUnityContainer container)
{
_container = container;
}
public void Initialize()
{
_container.RegisterType<ICamera, Camera>();
}
}
Then in the consumer, you obtain an instance from the container and use the object in the normal way.
public class HardwareConsumer
{
IUnityContainer _container;
public HardwareConsumer(IUnityContainer container)
{
_container = container;
}
public async void TakePhoto()
{
ICamera camera = _container.Resolve<ICamera>();
var result = await camera.TakePhoto;
}
}
But since this is using dependency injection to inject the container, if you have no other need for the container, you can also/instead inject the instance into your class:
public class HardwareConsumer2
{
ICamera _camera;
public HardwareConsumer2(ICamera camera)
{
_camera = camera;
}
public async void TakePhoto()
{
var result = await _camera.TakePhoto;
}
}
I'm working on a design that will allow me to mock out my database so I can test my views. I don't want to read a full book on IOC because I don't have the time right now. So, this is my home cooking.
Controller:
public ActionResult Milestone()
{
var result = SJMServiceFactory.GetService("Milestone");
return View(result);
}
Factory:
public static class SJMServiceFactory
{
public static DatabaseCollection_Result<T> GetService(string serviceName)
{
switch(serviceName)
{
case("Milestone"): return MileStoneService.GetMilestone();
case ("MilestoneMock"): return MileStoneService.GetMilestone(true);
default : return default(T);
}
}
}
MileStone
public class MileStoneService
{
public MileStoneService()
{
}
public static DatabaseCollection_Result<Milestone> GetMilestone(bool Mock)
{
if (Mock)
{
DatabaseCollection_Result<Milestone> mileStones = new DatabaseCollection_Result<Milestone>();
Milestone milestone1 = new Milestone();
milestone1.Name = "New";
Milestone milestone2 = new Milestone();
milestone2.Name = "Assessment";
mileStones.Results.Add(milestone1);
mileStones.Results.Add(milestone2);
return mileStones;
}
else
return null;
}
}
I figure I need to return an interface from my factory instead of that Generic type I tried and failed at doing. I don't know how to create an interface that works for all my models, is that the wrong direction?
Without reading a whole book (does one exist? IoC is a pretty small topic in the scheme of things):
Controller:
private readonly IMilestoneService milestoneSerivce;
public MilestoneController(IMilestoneService milestoneService)
{
this.milestoneService = milestoneService;
}
public ActionResult Milestone()
{
var result = milestoneService.GetMilestones();
return View(result);
}
IMilestoneService.cs
public interface IMilestoneService
{
DatabaseCollection_Result<Milestone> GetMilestones();
}
MilestoneService.cs
public class MilestoneService : IMilestoneService
{
public DatabaseCollection_Result<Milestone> GetMilestones()
{
return null;
}
}
MockMilestoneService.cs:
public class MockMilestoneService : IMilestoneService
{
public DatabaseCollection_Result<Milestone> GetMilestones()
{
DatabaseCollection_Result<Milestone> mileStones = new DatabaseCollection_Result<Milestone>();
Milestone milestone1 = new Milestone();
milestone1.Name = "New";
Milestone milestone2 = new Milestone();
milestone2.Name = "Assessment";
mileStones.Results.Add(milestone1);
mileStones.Results.Add(milestone2);
return mileStones;
}
}
Global.asax:
ObjectFactory.Configure(x => {
x.For<IMilestoneService>().Use<MilestoneService>();
// uncomment for test
//x.For<IMilestoneService>().Use<MockMilestoneService>();
});
This uses StructureMap, but I imagine the Ninject way to wiring up the dependencies is similar. Having never used Ninject I don't know for sure, but it looks like it might be something like:
Bind<IMilestoneService>().To<MilestoneService>();
In general though I wouldn't go about creating a whole new class to test your Views, I would use a mocking framework such as Moq to create mock objects and pass them to the View and then use Assertions about the ViewResult to determine if it worked correctly.
If you're doing interactive testing though and want to be detached from the database, this might be an ok approach.
Don't fear the learning curve. IoC is a reasonably simple concept.
Ninject was the first container I picked up, and it went smoothly. The only point I really struggled with for any amount of time was how to organize all the bindings, but even that was only an issue in large applications.
YMMV, but I'd say just diving in with Ninject or similar is better investment of time than DIY.
IoC with Ninject only takes code in a few places.
1: Bind you interfaces to implementations:
public class ServiceModule : NinjectModule
{
public override void Load() {
Bind<Common.Billing.AuthorizeNet.IBillingGatewayParametersFactory>().To<AuthorizeNetParameterFactory>();
Bind<Common.Billing.IBillingGateway>().To<Common.Billing.AuthorizeNet.BillingGateway>();
}
}
2: Use constructor arguments to pass dependencies into a class:
public class BillPayingService
{
private readonly IBillingGateway _billingGateway;
public BillPayingService(
IBillingGateway billingGateway
)
{
_billingGateway = billingGateway;
}
public void PayBills()
{
// ....
}
}
3: Initialize your container on application startup:
public static class Ioc
{
public static void Initialize()
{
var modules = new INinjectModule[] {
new ServicesModule(),
new DataModule()
new VideoProcessing.NinjectModule()
};
IKernel kernel = new Ninject.StandardKernel(modules);
}
}