Get Applicaton Path for iOS and Android - c#

I once used SQLite for my android application. I made a Queries.cs file where I had all the queries stored (createDatabase, insertDatabase etc). I had a string as a class variable where I stored the path ot the folder I wanted to put in my .db file. It looked like this:
private string folder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
Now I want the same or at least the folder where the application sits in. But this time I need a way that'll be supported from iOS and form Android because it is necessary for this project. Do you know how I can do that?
Many thanks in advance

There is no unified way provided in Xamarin.Forms for this. You can leverage the DependencyService to reach it from your shared code and still differentiate per platform. This could look like this, define an interface in your shared code:
public interface IFilesystemService
{
string GetAppRootFolder();
}
Now create an implementation on Android like this:
public class FilesystemServiceAndroid : IFilesystemService
{
public string GetAppRootFolder()
{
return System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
}
}
For iOS the idea is the same, only the implementation may differ. You can, of course, extend this class as you like with the ability to read or write files for example.
Don't forget to adorn your namespace of the implementation with the [assembly: Xamarin.Forms.Dependency (typeof (FilesystemServiceAndroid ))] attribute. Like so:
[assembly: Xamarin.Forms.Dependency (typeof (FilesystemServiceAndroid ))]
namespace YourAppName
{
public class FilesystemServiceAndroid : IFilesystemService
{
// ... code here
}
}
You can now retrieve it in your shared code like this: var path = DependencyService.Get<IFilesystemService>().GetAppRootFolder();

You should use a Dependency Service in order to get platform specific file paths. A great tutorial on how to use SQLite in Xamarin.Forms can be found here which can be used in platform specific code as well.

Related

Customizing nopCommerce

We are developing an nopCommerce based application. Our login page needs to be minimalistic and would need only an email id, password entry fields and a Login button.
Could you point me to best practices for achieving the above objective ?
Do I modify the corresponding pages found in \Presentation\Nop.Web\Views\Customer\ & controllers in \Presentation\Nop.Web\Controllers\
Or
Is there a better way of doing this and organizing all the modified files in one place/folder so that upgrading to future versions of nopCommerce will not be difficult ?
The requirement is to ensure that all the changes made to the project(views/controllers etc) are in one folder so that they are not overwritten when we upgrade to a newer version of nopCommerce.
I read somewhere that you can copy stuff you need to change (Login.chtml, CustomerController) to Themes/DefaultClean and then make your changes in this folder. I dont remember where i read it.
I feel doing so will make it that much easier to maintain our codebase because all your custom code is in one place/folder/sub folders
Is this a best practise? And is there a disadvantage to this method of doing things?
The best way to modify your nopCommerce project without changing anything in the core code would be to use the plugin functionality which is described here (assuming you're using the newest version 4.40).
To change the login page you would then need to create your modified version as a .cshtml file in your plugin. You then need to set this file as Content and set the Copy to Output Directory property to Copy if Newer or Copy Always.
You also need to implement the IViewLocationExpander interface so that the Razor Engine knows that it should use your custom Login Page. The implementation should look something like this:
public class MyViewLocationExpander : IViewLocationExpander
{
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
if(context.ViewName == "Login")
{
viewLocations = new[] { "PathToCustomLoginPage" }.Concat(viewLocations);
}
return viewLocations;
}
public void PopulateValues(ViewLocationExpanderContext context)
{
return;
}
}
After that you also need to register your ViewExpander by implementing the INopStartup interface. The implementation would look something like this:
public class MyStartup : INopStartup
{
public int Order => int.MaxValue;
public void Configure(IApplicationBuilder application)
{
}
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new MyViewLocationExpander());
});
}
}

Referencing a class that is not instantiated / does not yet exist

I have a Winforms application that is designed to integrate with external software packages. This application reads data from these packages and pushes it to our server where users log in and use our application (App).
public abstract ClassToImplement
{
public abstract void DefinedMethod1();
public abstract void DefinedMethod2();
}
When we designed the application it was intended to do 95% of the integration work with the remaining 5% (implementation class / App2) being developed by a consultant who's familiar with the 3rd party software.
public class Implemented : ClassToImplement{
public override void DefinedMethod1(...);
public override void DefinedMethod2(...);
}
The "App" outputs a Class Library which is then referenced in the Implementation (App2). In our design we created an Abstract Class and defined the methods. The idea was that the consultant would download the repo for the implementation class and include the App as a reference. They would then write the necessary code for the methods they're implementing, compile and "voila!"
For obvious reasons I don't want to share the source project with external developers, otherwise I'd just share the full solution and use a single app, and, while I know they can see a lot with the DLL reference, it is just easier for us to control everything.
The problem comes with App: the main application algorithm needs to instantiate the implementation class and then the program runs perfectly.
in Form1.cs of App:
ClassToImplement impObj = new Implemented();
impObj.DefinedMethod1();
impObj.DefinedMethod2();
The challenge I'm having is that I cannot build "App" to output a DLL without instantiating the Class. I cannot instantiate the Implemented Class as I haven't got the code (yet).
It would be great to know how to go about achieving this sort of abstraction with a dependancy on (yet) unwritten code and also, what is the technical term for what I'm trying to do?
To make it just "work" use a Func which returns an instance of the abstract class.
In your secret repo:
//Your "App" DLL Project
public abstract class ClassToImplement
{
public abstract void DefinedMethod1();
public abstract void DefinedMethod2();
}
public class App : Form
{
public App(Func<ClassToImplement> initiator)
{
InitializeComponent();
ClassToImplement ci = initiator.Invoke();
ci.DefinedMethod1();
ci.DefinedMethod2();
}
}
//This is in a separate project which will be your startup project internally
public class Dummy : ClassToImplement
{
public override void DefinedMethod1(){}
public override void DefinedMethod2(){}
}
public class Program
{
public static void Main()
{
Application.Run(new App(()=> new Dummy()));
}
}
In the repo shared with the consultant:
// In the repo which is shared with the consultant
// This will be the startup project on the build server, and when the consultant is testing.
public class Implementation : ClassToImplement
{
public override void DefinedMethod1(){}
public override void DefinedMethod2(){}
}
public class Program
{
public static void Main()
{
Application.Run(new App(()=> new Implementation()));
}
}
On your build server, you can pull from both the repos, and set the startup project as the one given to the consultant. But when you are testing and developing internally, you set the startup project to your version with an implementation that does nothing.
As a side note, if you think what you are doing needs to be protected from consultants who have signed a confidentiality agreement, make sure to obfuscate when you do a release.
This is a two-step process usually:
Locate and load the assembly/dll:
Assembly assembly = Assembly.LoadFrom(DLL);
Instantiate the implemented class:
Type type = assembly.GetType(FullNameOfImplemented);
AppInstance = (ClassToImplement)Activator.CreateInstance(type, parameters);
The process you are looking for is often called stubbing. In this case you've chosen to encapsulate the integration functionality in a library, not web services, but the principle is the same.
The idea was that the consultant would download the repo for the implementation class and include the App as a reference.
This sounds like you've got the dependency relationship the wrong way round. If the consultant's code references your app, then your app can't reference it - it'd be a circular dependency. Instead, factor your app something more in line with the following:
App
|
|
App.Integration.Contracts
^ ^
| |
| App.Integration.Stub
|
App.Integration
The abstract class - it could just as easily be an interface in C# - resides in the Contracts assembly. This is the only compiled dependency your application has. Then at runtime use configuration to load either the stub, or the full implementation using an IoC container. An example is Unity for which you will need its configuration API. Reference the true type to use in the configuration file and change only that to update your application to use the full functionality.
First off I think you need to implement a proper plugin system if you dont want to share your code with that other developers.
Second you should code against your interface and not against its implementation. First because you dont have it and second because you may want to switch implementations for different 3rd party software.
If you need an instance for testing or stuff, you can use a handwritten mock or an mocking framework. If you need a real instance later on (when the other developers have delivered) you can use some design pattern like factory pattern or others for the creation. Try to avoid the new keyword if you want to change implementations later on.

How can I horribly twist a c# project to read its class library's app.config files

So let me start off by saying "I know this isn't a best practice" and that I do not want to add the information from the app.config files to the web.config file... I've got a project that is a class library itself and it will be using a lot of class libraries as well.
Typically in my unit test project (used for testing) or my web project (that uses the lib in production) I have to add all of the configuration information. These libraries aren't going to be called differently from each project so I'm looking for a way to get the calling project to read the callee project's config file.
I've looked online and the only two things I've found so far are:
1) Don't do it. You need to add the information to the calling project's config file
example a) Read from App.config in a Class Library project
example b) Class Library project in ASP.NET reading from web.config and not app.config
example c) .Net app.config in library project
2) You shouldn't do it but I know how (no how to included :/)
example a) app.config for a class library
I've been doing it the "right" way for a while and that has left me with lots of web.config and test project config files with info duplicated from class lib app.config files. I really do think that there is a specific, justified use case for doing this.
Thanks!
The best practice that I know of is to avoid direct dependency on app.config/web.config from classes in your library, or maybe even classes in general. That doesn't mean that you don't use app.config. It means that your classes don't know they're using it.
For example,
public class MyClassThatDependsOnSomeSettings
{
private readonly ISettings _settings;
public MyClassThatDependsOnSomeSettings(ISettings settings)
{
_settings = settings;
}
public void DoSomething()
{
var settingA = _settings.SettingA;
}
}
public interface ISettings
{
int SettingA {get;}
string SettingB {get;}
}
Now you can consider MyClassThatDependsOnSomeSettings done. It doesn't require any access to a .config file. It just requires an instance of something that implements ISettings. That can read from .config.
public class SettingsFromConfiguration : ISettings
{
public int SettingA
{
get
{
string setting = ConfigurationManager.AppSettings["settingA"];
int value = 0;
int.TryParse(setting, out value);
return value;
}
}
public string SettingB
{
get { return ConfigurationManager.AppSettings["settingB"];}
}
}
Does it look like this just moves things around and does the same thing anyway? It does, almost. The big difference is that while you can use an implementation of ISettings that reads from app.config, you can also write other implementations. You can write one that uses hard-coded values, you could write a custom configuration section instead of using AppSettings, or if down the road you have an application with a JSON configuration file and no AppSettings your class can still work.
This applies the Dependency Inversion, which beneath everything means that classes should depend on abstractions (like interfaces) not concrete implementations.
Putting a requirement for ISettings in the constructor is called Dependency Injection, specifically constructor injection.

Nancy: is there a Server.MapPath("~/") equivalent?

I can't seem to find an equivalent in Nancy for System.Web.HttpContext.Current.Server.MapPath() in the Nancy framework.
I just want to load a textfile relative to the application service.
I see this in the assembly
using Nancy;
using System;
namespace Nancy.Hosting.Self
{
public class FileSystemRootPathProvider : IRootPathProvider, IHideObjectMembers
{
public FileSystemRootPathProvider();
public string GetRootPath();
}
}
I'm not sure how to use.
update: I just figured out anything I need to load can just be read/written from the bin/relase/ directory. Is that the assumed way to do it in a Nancy Self Hosting environment? I guess that would make sense.
You can take a dependency on IRootPathProvider and use that to call GetRootPath() that will give you the root of your application and you can add from there (I would recommend using Path.Combine)
If you need this in a static class (such as an HtmlHelpers extension) where the IRootPathProvider dependency can't be injected, at least AFAIK, you can use AppDomain.CurrentDomain.BaseDirectory which is what DefaultRootPathProvider uses under the hood for .Net 4.x: https://github.com/NancyFx/Nancy/blob/master/src/Nancy/DefaultRootPathProvider.cs

MvvmCross vnext: merge plugins with monodroid

I'm trying to merge plugins library projects into a single one (for example, Location + PhoneCallTask). It works perfectly with wp7, but I get an unhandled exception with monodroid:
Could not load file or assembly 'Cirrious.MvvmCross.Plugins.Location.Droid.dll'
Of course, the location plugin is referenced in 'Cirrious.MvvmCross.Plugins.Droid.dll', the merged library.
Is there a way to point to the merged library path?
Having considered your question more fully...
I'm still not entirely sure what a merge plugin is, but I think the problem you are seeing must be down to the way that MvvmCross-MonoDroid uses file conventions to load plugins while all the other platforms force the user to provide explicit factory methods for each plugin.
The reason for this difference is because the file conventions are (IMO) the nicest way of doing this... but all the other platforms put security and/or compilation issues in the way which meant that alternative mechanisms had to be used...
The easiest thing for you to do is probably to switch the setup of your MonoDroid app to use the loader conventions too.
To do this:
in Setup.cs override CreatePluginManager() to:
protected override IMvxPluginManager CreatePluginManager()
{
var toReturn = new MvxLoaderBasedPluginManager();
var registry = new MvxLoaderPluginRegistry(".Droid", toReturn.Loaders);
AddPluginsLoaders(registry);
return toReturn;
}
and then provide a AddPluginsLoaders() implementation like:
protected virtual void AddPluginsLoaders(Cirrious.MvvmCross.Platform.MvxLoaderPluginRegistry loaders)
{
loaders.AddConventionalPlugin<Cirrious.MvvmCross.Plugins.Visibility.Droid.Plugin>();
loaders.AddConventionalPlugin<Cirrious.MvvmCross.Plugins.Location.Droid.Plugin>();
loaders.AddConventionalPlugin<Cirrious.MvvmCross.Plugins.Phone.Droid.Plugin>();
loaders.AddConventionalPlugin<AlphaPage.MvvmCross.Plugins.Mega.Droid.Plugin>();
// etc
}
Short answer:
I'm guessing you need to:
check that your namespaces and assembly names are all of the same convention
check that you have referenced both the core plugin assembly and the correct plugin implementation within the UI.Droid project
Longer answer (based on some notes I already had - will be published soon):
If you were to build an entirely new plugin, then you would:
1. Create a central shared plugin
This would be Portable Class library - say AlphaPage.MvvmCross.Plugins.Mega
Within that central shared PCL, you would put whatever portable code was available - often this might only be a few service Interface definitions - e.g.
public interface IAlphaService { ... }
and
public interface IPageService { ... }
You'd then add the PluginManager for that plugin which would just add the boiler-plate of:
public class PluginLoader
: IMvxPluginLoader
, IMvxServiceConsumer<IMvxPluginManager>
{
public static readonly PluginLoader Instance = new PluginLoader();
#region Implementation of IMvxPluginLoader
public void EnsureLoaded()
{
var manager = this.GetService<IMvxPluginManager>();
manager.EnsureLoaded<PluginLoader>();
}
#endregion
}
2. Create the specific plugin implementations
For each platform, you would then implement the plugin - e.g. you might implement AlphaPage.MvvmCross.Plugins.Mega.WindowsPhone and AlphaPage.MvvmCross.Plugins.Mega.Droid
Within each of these you will implement the native classes which provide the services:
public class MyAlphaService : IAlphaService { ... }
and
public class MyPageService : IPageService { ... }
Finally each plugin would then provide the boilerplate plugin implementation:
public class Plugin
: IMvxPlugin
, IMvxServiceProducer
{
#region Implementation of IMvxPlugin
public void Load()
{
// alpha registered as a singleton
this.RegisterServiceInstance<IAlphaService>(new MyAlphaService());
// page registered as a type
this.RegisterServiceType<IPageService, MyPageService>();
}
#endregion
}
3. Instantiation of plugins
Each UI client will have to initialise the plugins.
This is done by the end UI client adding library references to:
the shared core plugin
the appropriate plugin implementation
3.1 WinRT, WindowsPhone and MonoTouch
Then, for WinRT, WindowsPhone and MonoTouch clients, you also need to provide a Loader accessor in setup.cs - like:
protected override void AddPluginsLoaders(Cirrious.MvvmCross.Platform.MvxLoaderPluginRegistry loaders)
{
loaders.AddConventionalPlugin<AlphaPage.MvvmCross.Plugins.Mega.WindowsPhone.Plugin>();
base.AddPluginsLoaders(loaders);
}
Note that Convention is used here - so it's important that AlphaPage.MvvmCross.Plugins.Mega.WindowsPhone.Plugin implements the WindowsPhone plugin for AlphaPage.MvvmCross.Plugins.Mega.PluginLoader
3.2 MonoDroid
For MonoDroid clients, you don't need to add this setup step - because MonoDroid has less Assembly.Load restrictions than the other platforms - and ao can load the plugins from file. But for this to work, it's important that the assembly names match - if the PluginLoader is AlphaPage.MvvmCross.Plugins.Mega.PluginLoader then the conventions will try to load the plugin from AlphaPage.MvvmCross.Plugins.Mega.Droid.dll
4. Use of plugin services
After this setup, then applications should finally be able to access the plugins by:
adding a reference the Shared core portable library
at some time calling AlphaPage.MvvmCross.Plugins.Mega.PluginLoader.Instance.EnsureLoaded()
then accessing the individual services using this.GetService<IAlphaService>() or this.GetService<IPageService>()
5. Pure portable plugins
Some plugins can be 'pure portable'
In this case they don't need any specialization for each platform, and no step 3 is required.
For an example of this, see the Json implementation - https://github.com/slodge/MvvmCross/tree/vnext/Cirrious/Plugins/Json

Categories