What is typically included in the OnStart or a Xamarin.forms application? - xamarin

My application uses a database and the connection is currently created with this code when the DataAccess is first referenced:
public static DataAccess DataAccess
{
get
{
if (dataAccess == null)
{
dataAccess = new DataAccess();
}
return dataAccess;
}
}
Would it be more appropriate to put this on the OnStart? I'm just not sure as the current developer did it in the way above.
protected override void OnStart()
{
// Handle when your app starts
}

Related

Replace default IoC container in MvvmCross

Since MvvmCross v7 sticks on its own IoC container, I would like to replace it with the .NET Core one in order to have an easier life when registering third party libraries such as IHttpClientFactory, Polly, Automapper, etc. through already built-in extensions methods.
To achieve this, I've successfully created a class that implementas MvxSingleton<IMvxIoCProvider> described as follow:
public class HostingAdapter : MvxSingleton<IMvxIoCProvider>, IMvxIoCProvider
{
private IServiceProvider ServiceProvider;
private IServiceCollection ServiceCollection;
public HostingAdapter()
{
var host = Host
.ConfigureServices((context, serviceCollection) =>
{
// Configure local services
ConfigureServices(context, serviceCollection);
ServiceCollection = serviceCollection;
ServiceProvider = ServiceCollection.BuildServiceProvider();
})
.Build();
}
public void RegisterType<TFrom, TTo>() where TFrom : class where TTo : class, TFrom
{
ServiceCollection.AddTransient<TFrom, TTo>();
ServiceProvider = ServiceCollection.BuildServiceProvider();
}
public T GetSingleton<T>() where T : class
{
return ServiceProvider.GetRequiredService<T>();
}
public object GetSingleton(Type type)
{
return ServiceProvider.GetRequiredService(type);
}
.. and all the required methods requested by the interface.
Then on the platform specific side I override the IoC creation as follow:
protected override IMvxIoCProvider CreateIocProvider()
{
var hostingAdapter = new HostingAdapter();
return hostingAdapter;
}
The code seems to work but as soon as the app starts Mvx registers its own "extra" services such as the IMvxLoggerProvider, IMvxSettings and so on. And here issues come:
ServiceProvider = ServiceCollection.BuildServiceProvider(); is called during the Host initialization but Mvx still continue to register services after that. This means IServiceProvider is not 'in sync' with IServiceCollection and a new ServiceCollection.BuildServiceProvider(); call is needed. I temporarily solved updating the provider at each collection registration (like the code above) but I'm aware this affects performances. Anyone knows how to workaround this?
There are plenty of Mvx services that are not registered so the app fails to start. These are the IMvxLogProvider, IMvxAndroidLifetimeMonitor, IIMvxSettings, IMvxStart, etc. I just wonder, why? How can let Mvx handle the registration in my container of all what it needs to start? I partially solved some of them such as the logger thing replacing the default with a custom one, but other callbacks like InitializeLifetimeMonitor are called too late for being registered.
Do I need to change anything in my MvxApplication than the most standard implementation?
Am I really forced to replace the standard IoC container? How can I handle the IServiceCollection's extension methods that 3rd party libraries expose like services.AddHttpClient();?
If it needs, I am on Xamarin classic using the Droid platform. Thanks
Deliberately inspired by Unity.Microsoft.DependencyInjection repository I've workarounded this approaching the problem the other way round: instead of replacing the default IoC container, I manually initialize an IServiceCollection instance and I add it to the Mvx's IoC provider.
To achieve this, I've used the following code:
public class App : MvxApplication
{
public override void Initialize()
{
base.Initialize();
InitializeServiceCollection();
CreatableTypes()
.EndingWith("Service")
.AsInterfaces()
.RegisterAsLazySingleton();
RegisterAppStart<HomeViewModel>();
}
private static void InitializeServiceCollection()
{
IServiceCollection serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
MapServiceCollectionToMvx(serviceProvider, serviceCollection);
}
private static void ConfigureServices(IServiceCollection serviceCollection)
{
serviceCollection.AddHttpClient();
}
private static void MapServiceCollectionToMvx(IServiceProvider serviceProvider,
IServiceCollection serviceCollection)
{
foreach (var serviceDescriptor in serviceCollection)
{
if (serviceDescriptor.ImplementationType != null)
{
Mvx.IoCProvider.RegisterType(serviceDescriptor.ServiceType, serviceDescriptor.ImplementationType);
}
else if (serviceDescriptor.ImplementationFactory != null)
{
var instance = serviceDescriptor.ImplementationFactory(serviceProvider);
Mvx.IoCProvider.RegisterSingleton(serviceDescriptor.ServiceType, instance);
}
else if (serviceDescriptor.ImplementationInstance != null)
{
Mvx.IoCProvider.RegisterSingleton(serviceDescriptor.ServiceType, serviceDescriptor.ImplementationInstance);
}
else
{
throw new InvalidOperationException("Unsupported registration type");
}
}
}
}

How to add a ViewModel for new pages of Xamarin Native iOS & Android apps

Context: I am handed this massive enterprise iOS & Android Xamarin Native applications that doesn't use ViewModels or any MVVM framework. It does have a separated Network services layer and it has a lot of pages, so starting over won't make any sense.
Why the change is needed: No MVVM, the services layer is called directly from the UI classes (Fragments & ViewControllers), and there is no good abstraction. So I will start with 1 view and then create TechDebt to transform the rest of the app.
What I know:
Adding MVVM frameworks require creating extensive changes, especially to use Navigation services for Navigating the views, and are best done if added when green-fielding the application.
As seen here, Android has an easy way of using a ViewModel but I won't be able to use that for iOS then.
I also know that I can launch a Xamarin Forms page instead and that will be all ready for MVVM, since I can just assign the BindingContext property to an instance of the ViewModel.
What I need: I need to create one new page for iOS & one for Android. I want to be able to create a ViewModel that's shared between iOS & Android. I want to be able to use it for a single view that I am creating and it should be initialized when the page is loaded.
How can I add 1 viewmodel that's shared by a ViewController & a Fragment? Am I missing something, is it much easier than I am making it?
Ended up being able to use MvvmLight for this. Added the Nuget package to the projects, Created a ViewModelBase in the Core Shared Library Project:
public abstract class ViewModelBase : GalaSoft.MvvmLight.ViewModelBase
{
private PropertyChangedEventHandler propertyChangedEventHandler;
protected bool IsLoading { get; set; }
public bool RegisteredPropertyEventHandler { get; set; }
public const string ErrorMessagePropertyName = "ErrorMessage";
public string ErrorMessage { get; set; }
public string SuccessMessage { get; set; }
public void RegisterPropertyEventHandler(PropertyChangedEventHandler propertyChangedEventHandler)
{
this.propertyChangedEventHandler = propertyChangedEventHandler;
this.PropertyChanged += propertyChangedEventHandler;
this.RegisteredPropertyEventHandler = true;
}
public void UnegisterPropertyEventHandler()
{
if (this.RegisteredPropertyEventHandler)
{
this.PropertyChanged -= propertyChangedEventHandler;
this.RegisteredPropertyEventHandler = false;
this.propertyChangedEventHandler = null;
}
}
public void TearDown()
{
this.UnegisterPropertyEventHandler();
}
protected void NotifyError (string message)
{
this.ErrorMessage = message;
RaisePropertyChanged (() => ErrorMessage);
}
}
and a ViewModelLocator
public class ViewModelLocator
{
public const string ABCPageKey = "ABCPage";
public ABCViewModel ABC
{
get
{
return ServiceLocator.Current.GetInstance<ABCViewModel> ();
}
}
public ViewModelLocator ()
{
ServiceLocator.SetLocatorProvider (() => SimpleIoc.Default);
// Register all of the view models
SimpleIoc.Default.Register<ABCViewModel> ();
}
public static void Cleanup ()
{
}
public T GetViewModel<T> ()
{
return ServiceLocator.Current.GetInstance<T> ();
}
}
On the iOS side, I already had a BaseUIViewController, so I created a BaseViewModelUIViewController on top of it
public abstract partial class BaseViewModelUIViewController<T> : BaseUIViewController where T : ViewModelBase
{
public T ViewModel
{
get
{
return App.Locator.GetViewModel<T> ();
}
}
public BaseViewModelUIViewController (IntPtr handle) : base (handle)
{
}
internal virtual void ViewModelPropertyChangedHandler (object sender, PropertyChangedEventArgs e)
{
Console.WriteLine (string.Format ("****** Property Changed for {0} in {1}", e.PropertyName, this.GetType ().Name));
switch (e.PropertyName)
{
default:
break;
}
}
}
And then Android, similarly I already had a BaseFragment, so I created a BaseViewModelFragment on top of it
public class BaseViewModelFragment<T> : BaseFragment where T : ViewModelBase
{
public T ViewModel
{
get
{
return App.Locator.GetViewModel<T> ();
}
}
public BaseViewModelFragment (string title) : base (title)
{
}
internal virtual void ViewModelPropertyChangedHandler (object sender, PropertyChangedEventArgs e)
{
Console.WriteLine (string.Format ("****** Property Changed for {0} in {1}", e.PropertyName, this.GetType ().Name));
switch (e.PropertyName)
{
default:
break;
}
}
public override void OnDestroyView ()
{
this.ViewModel.TearDown ();
base.OnDestroyView ();
}
}
I hope it makes sense to other people looking for solutions.
Creating ViewModels: So naturally, for every new ViewModel created, I had to register it in the ViewModelLocator.
Using ViewModels: In terms of usage, you can simply use the ViewModel in the UI by inheriting from the ": BaseViewModelUIViewController" for iOS or from ": BaseViewModelFragment" for Android
Unfortunately you don't miss anything, all your claims are proper and you have properly listed various directions that you can take (and that you don't like).
Xamarin.Android and Xamarin.iOS are not made with data binding in mind, but rather with using the native interfaces, only Xamarin.Forms is made for the data binding. The capabilities of native platforms to use the data binding is limited (if it existed it would be incompatible among the platforms and you would have to make separate view models, and there is not data binding for iOS as of now anyway).
So basically there is no data binding in Xamarin.iOS and Xamarin.Android. It is completely up to you to abstract the shared business model and connect it with the user interface.

How to Integrate Prism, Unity, and Enterprise Library

I'm building a WPF application. I'm using Prism 4, and Unity. I want to add two Enterprise Library 5 blocks to the application, Logging and Exception Handling. I have a singleton LoggerFacadeCustom.cs in my Infrastructure class that supports the ILoggerFacade and I've created it in my bootstrapper, and it is generating log files. It "news" up a unity container in its constructor (second code block)
Where do I add the container.resolve for ExceptionManager? How do I connect the Exception handling block to ILoggerFacade in my bootstrapper? How do I get all the exceptions to come out in the same log? Here is my existing bootstrapper.cs
public class Bootstrapper : UnityBootstrapper {
protected override ILoggerFacade CreateLogger() {
return LoggerFacadeCustom.Instance;
}
protected override DependencyObject CreateShell() {
return Container.Resolve<Shell>();
}
protected override void InitializeShell() {
base.InitializeShell();
App.Current.MainWindow = (Window)Shell;
App.Current.MainWindow.Show();
//Other shell stuff...
}
protected override IModuleCatalog CreateModuleCatalog() {
var catalog = new ModuleCatalog();
//These primary modules must register their own services as if they were acting independantly
catalog.AddModule(typeof(XmlCommentMergeModule));
//These support modules require at least one primary module above to be added first
catalog.AddModule(typeof(ToolboxHeaderModule));
catalog.AddModule(typeof(ToolboxFooterModule));
catalog.AddModule(typeof(ToolboxStartModule));
return catalog;
}
}
LoggerFacadeCustom:
public class LoggerFacadeCustom : ILoggerFacade {
private static readonly LoggerFacadeCustom _instance = new LoggerFacadeCustom();
public static LoggerFacadeCustom Instance { get { return _instance; } }
private LoggerFacadeCustom() {
var container = new UnityContainer();
container.AddNewExtension<EnterpriseLibraryCoreExtension>();
_logWriter = container.Resolve<LogWriter>();
}
private readonly LogWriter _logWriter;
public void Write(string message) { Write(message, null); }
public void Write(string message, string category, int priority) {
_logWriter.Write(message, category, priority);
}
public void Write(string message, Dictionary<string, object> properties) {
_logWriter.Write(message, LiteralString.LogCategoryProcess, properties);
}
#region ILoggerFacade Members
public void Log(string message, Category category, Priority priority) {
throw new NotImplementedException();
}
#endregion
}
Your bootstrapper is the Composition Root of your application. You should register all dependencies there. And only there. You should never reference the container directly outside the composition root.
If your classes have a dependency you should inject that dependency using a pattern like constructor injection.
Don't use static classes. Static kills dependency injection and testability and it hides dependencies to a point where everything is referenced from everywhere.
Make your logger facade a constructor parameter. You can do the same with the error handling block.
Don't use the container as a ServiceLocator. That is considered an anti-pattern in modern software architecture.

Refresh a list webpart to reflect the item added in sharepoint 2010 developed using visual studio 2010

I have a visual webpart that list the students.
Also have a webpart to add/edit student.
After deploying the application, I created new webpart page and added CreateStudent webpart in a zone and ListStudent webpart in another zone.
When I add a student I need to find that student details in the grid of ListStudent webpart.
I think I need to connect the two webparts making CreateStudent webpart as provider webpart and ListStudent webpart as consumer webpart, but my doubt is, I dont need to pass any particular value to the ListStudent webpart.
I have a funstion call in ListStudent webpart Page_Load which set the datasource of the gridview and binding it. How can this be done?
Here is link which meets your needs,
I think it'll be helpfull to you.
http://www.dotnetcurry.com/ShowArticle.aspx?ID=678
Thnks and regards.
It's another link which exactly meets your need,
http://blogs.msdn.com/b/pranab/archive/2008/07/02/step-by-step-creating-connected-sharepoint-web-parts-using-iwebpartfield-interface-and-using-editor-part-and-user-controls.aspx
Here are simple provider and consumer Web Parts. The provider UI accepts a text field that it passes to the consumer Web Part which simply outputs it. The connection between the Web Parts is the following interface:
namespace ConnectedWebParts
{
public interface IParcel
{
string ID { get; }
}
}
The Provider Web Part implements this interface and must have a method with the attribute ConnectionProvider that returns itself (since it implements the interface):
namespace ConnectedWebParts
{
public class ProviderWebPart : WebPart, IParcel
{
protected TextBox txtParcelID;
protected Button btnSubmit;
private string _parcelID = "";
protected override void CreateChildControls()
{
txtParcelID = new TextBox() { ID = "txtParcelID" };
btnSubmit = new Button() { ID = "btnSubmit", Text="Submit"};
btnSubmit.Click += btnSubmit_Click;
this.Controls.Add(txtParcelID);
this.Controls.Add(btnSubmit);
}
void btnSubmit_Click(object sender, EventArgs e)
{
_parcelID = txtParcelID.Text;
}
[ConnectionProvider("Parcel ID")]
public IParcel GetParcelProvider()
{
return this;
}
string IParcel.ID
{
get { this.EnsureChildControls(); return _parcelID; }
}
}
}
The Consumer Web Part must define a method with a ConnectionConsumer attribute that accepts an object that implements the connection interface (the provider Web Part) as a parameter:
namespace ConnectedWebParts
{
public class ConsumerWebPart : WebPart
{
protected IParcel _provider;
protected Label lblParcelID;
protected override void CreateChildControls()
{
lblParcelID = new Label();
if (_provider != null && !String.IsNullOrEmpty(_provider.ID))
lblParcelID.Text = _provider.ID;
this.Controls.Add(lblParcelID);
}
[ConnectionConsumer("Parcel ID")]
public void RegisterParcelProvider(IParcel provider)
{
_provider = provider;
}
}
}

Nhibernate with windows form

I have a asp.net application with Nihbernate setup, now I want to convert it to Windows form application.
Here is the code which have been setup in the Global.asax.cs. Can anyone give me some code sample how to do this in Windows form?
protected void Application_BeginRequest(object sender, EventArgs e)
{
ManagedWebSessionContext.Bind(HttpContext.Current, SessionManager.SessionFactory.OpenSession());
}
protected void Application_EndRequest(object sender, EventArgs e)
{
ISession session = ManagedWebSessionContext.Unbind(HttpContext.Current, SessionManager.SessionFactory);
if (session != null)
{
try
{
if (session.Transaction != null && session.Transaction.IsActive)
{
session.Transaction.Rollback();
}
else
{
session.Flush();
}
}
finally
{
session.Close();
}
}
}
Well, there are several methods for accessing ISessionFactory in statefull application (and a desktop application is that kind of application), among them:
Singleton
You could build the session factory once during the startup of your program and access it through a static singleton class.
This would force the application to use only one instance of the session factory.
example:
public sealed class NHibernateHelper
{
private static ISessionFactory SessionFactory;
private static readonly Configuration NhibernateConfig;
// ....
static NHibernateHelper()
{
NhibernateConfig = new Configuration().Configure();
SessionFactory = NhibernateConfig.BuildSessionFactory();
}
public static ISessionFactory GetSessionFactory()
{
return SessionFactory;
}
// ....
}
... and access the session factory through GetSessionFactory method all over the application.
Context Object and/or Dependency Injection
You could build the session factory from configuration and pass it through a context object all over the application.
example:
during startup:
// here you configure NHibernate.
ISessionFactory _sessionFactory = BuildMySessionFactory();
// ...
ObjectFactory.Initialize(x =>
{
x.For<IPatientRepository>()
.Use<StandardPatientRepository>()
.Ctor<ISessionFactory>().Is(_sessionFactory);
// ... initialize the rest of your repositories...
});
then:
public class StandardPatientRepository : IPatientRepository
{
private readonly ISessionFactory _sessionFactory;
public StandardPatientRepository(ISessionFactory sessionFactory)
{
if (sessionFactory == null)
throw new ArgumentNullException("sessionFactory");
_sessionFactory = sessionFactory;
}
public virtual Patient Get(Guid id)
{
using (IStatelessSession session =
_sessionFactory.OpenStatelessSession())
{
return session.Get<Patient>(id);
}
}
// the rest of data-access methods.
}
then in your classes that will make use of the data (ie. use the repositories) you will use:
Patient = ObjectFactory.GetInstance<IPatientRepository>().Get(patient);
In my opinion the second method is better as I think that singleton in most cases is an anti-pattern. The second approach will give you more control over your data layer, you will know who and when is accessing it.
Here is a well done and extensive sample application using NHibernate in a desktop application:
Building a Desktop To-Do Application with NHibernate
Managing the NHibernate session in a desktop application tends to be a lot more involved than managing the NHibernate session in a web application.

Resources