App crashes when Link All Assemblies enabled - xamarin

I am trying to reduce app size and enabled "Link All Assemblies", but my app crashes with following error
MvvmCross.Platform.Exceptions.MvxException: Failed to construct and initialize ViewModel for type Japam.Core.ViewModels.MantraasViewModel from locator MvxDefaultViewModelLocator - check InnerException for more information
I tried
--linkskip=mvvmcross.platform.ios
--linkskip=mvvmcross.core
--linkskip=mvvmcross.platform
but no luck, kept preserve attribute at assembly level of my core pcl project.
Also added a couple of more methods in LinkerPleaseIncludefile
public void Include(MvvmCross.Platform.IoC.MvxPropertyInjection injection)
{
injection = new MvvmCross.Platform.IoC.MvxPropertyInjection();
}
public void Include(MvxDefaultViewModelLocator locator)
{
locator = new MvxDefaultViewModelLocator();
}
but no use, could somebody help me find out what is missing
MvvmCross.Platform.Exceptions.MvxException: Failed to construct and initialize ViewModel for type
Japam.Core.ViewModels.MantraasViewModel from locator
MvxDefaultViewModelLocator - check InnerException for more information
---> MvvmCross.Platform.Exceptions.MvxException: Problem creating viewModel of type MantraasViewModel --->
MvvmCross.Platform.Exceptions.MvxIoCResolveException: Failed to
construct MantraasViewModel --->
System.Reflection.TargetInvocationException: Exception has been thrown
by the target of an invocation. --->
MvvmCross.Platform.Exceptions.MvxIoCResolveException: Failed to
resolve parameter for parameter sqliteConnectionFactory of type
IMvxSqliteConnectionFactory when creating
Japam.Core.Services.DataServices.MantraService
at MvvmCross.Platform.IoC.MvxSimpleIoCContainer.GetIoCParameterValues
(System.Type type, System.Reflection.ConstructorInfo firstConstructor)
[0x00036] in D:\git\MvvmCross\MvvmCross\Platform\Platform\IoC\

Finally I found the issue, it's SQLite problem so I added below three commands and it started working hope this helps someone else
--linkskip=MvvmCross.Plugins.Sqlite
--linkskip=SQLite-net
--linkskip=MvvmCross.Plugins.Sqlite.iOS
I should kept SQLite earlier it self my last project I did kept SQLite but forgot this time

Related

Xamarin Prism Unable to navigate to LoginPageViewModel

I am trying to make my Xamarin Project use MVVM with Prism and DryIoc.
I mostly want to use AutoRegistration like below:
[AutoRegisterForNavigation]
...
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
//Pages
containerRegistry.RegisterForNavigation<NavigationPage>();
//Services
containerRegistry.RegisterSingleton<ILocalDatabase, LocalDatabase>();
containerRegistry.RegisterSingleton<IUserProfileDataStore, UserProfileDataStore>();
containerRegistry.RegisterSingleton<IApplicationSettings, ApplicationSettings>();
containerRegistry.RegisterSingleton<ILogger, Logger>();
containerRegistry.RegisterSingleton<IApiService, ApiService>();
containerRegistry.RegisterSingleton<IUserSession, UserSession>();
containerRegistry.Register<IBrowser, BrowserImplementation>();
containerRegistry.Register<IConnectivity, ConnectivityImplementation();
containerRegistry.Register<IFileSystem, FileSystemImplementation>();
containerRegistry.Register<ICoreServices, CoreServices>();
}
I have also tried Manual Registration:
containerRegistry.RegisterForNavigation<LoginPage, LoginPageViewModel>();
Neither works, It hits the Login Page code behind then breaks with the following error:
Exception - High: Prism.Ioc.ContainerResolutionException:
An unexpected error occurred while resolving 'AppetiteApp.ViewModels.LoginPageViewModel' --->
DryIoc.ContainerException: code: UnableToResolveUnknownService; message: Unable to resolve
Resolution root AppetiteApp.ViewModels.LoginPageViewModel
with passed arguments [value(Prism.Navigation.ErrorReportingNavigationService)]
**System.NullReferenceException:** 'Object reference not set to an instance of an object.'
I've also tried using a Linker file setting it's build action to "linkdescription"
As for my Login Page here is the declaration
public LoginPageViewModel(ICoreServices coreServices)
: base(coreServices)
The constructor of LoginPageViewModel requires the ICoreServices argument which is registered.
The error message says that the LoginPageViewModel itself is unknown to the IoC - it means the type LoginPageViewModel is not directly registered and not found through dynamic registrations or unknown service resolvers.
I am not a user of the Xamarin Prism so I am not sure about its mechanism for registering the view models.
Btw, this part of error
Resolution root AppetiteApp.ViewModels.LoginPageViewModel
with passed arguments [value(Prism.Navigation.ErrorReportingNavigationService)]
basically means the view-model was resolved via the foollowing call resolver.Resolve(typeof(LoginPageViewModel), args: new[] { errorReportingNavigationService })
Hope it will help you or someone knowledgeable in Xamarin to track the error cause.
So Once I investigated Inside of ICoreServices I commented out each of the dependencies then discovered that IUserSession was the once causing problems then I dug into that and discovered that the dependences for IAppInfo and IVersionTracking were missing in the App.Xaml.cs registr tyepes so I added that and then it worked!
containerRegistry.Register<IAppInfo, AppInfoImplementation>();
containerRegistry.Register<IVersionTracking, VersionTrackingImplementation>();

Xamarin Forms - InitializeComponent exception

I'm getting an exception on a Xamarin Forms content page with Xaml, on the initializecomponent method. The exception occurs on the generated xaml.gs page. I haven't changed any code form a working version. Maybe something upstream has changed. The exception message is ""
Value cannot be null.
Parameter name: binding
stack trace:
at Xamarin.Forms.BindableObject.SetBinding (Xamarin.Forms.BindableProperty targetProperty, Xamarin.Forms.BindingBase binding, System.Boolean fromStyle) [0x00011] in D:\a\1\s\Xamarin.Forms.Core\BindableObject.cs:293
at Xamarin.Forms.BindableObject.SetBinding (Xamarin.Forms.BindableProperty targetProperty, Xamarin.Forms.BindingBase binding) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\BindableObject.cs:117
at ....LoginPage.InitializeComponent () [0x00045] in ...\obj\Debug\netstandard2.0\Views\Navigation\Login.xaml.g.cs:34
at FieldServices.LoginPage..ctor () [0x0002b] in ..\Views\Navigation\Login.xaml.cs:25
where occurrs:
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG", "0.0.0.0")]
private void InitializeComponent() {
global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(LoginPage));
email = global::Xamarin.Forms.NameScopeExtensions.FindByName(this, "email");
password = global::Xamarin.Forms.NameScopeExtensions.FindByName(this, "password");
loginButton = global::Xamarin.Forms.NameScopeExtensions.FindByName(this, "loginButton");
}
I rarely get this error when pulling code down. First, double-check that your code is fine. In this case, I would make sure all the bindings are named correctly with no typos.
In the event that you cannot find an error and are thoroughly convinced there is nothing wrong with the code, try steps like
Clean and Rebuild
Close your Visual Studio and restart it
Hopefully the error is solved as easy as this.
On top of cleaning and rebuilding, manually delete all the obj and bin folders from your solution directory. Those xaml.gs files are generated files and sometimes they seem to not regenerate when they should.
I'm getting an exception on a Xamarin Forms content page with Xaml, on the initializecomponent method. The exception occurs on the generated xaml.gs page. I haven't changed any code form a working version. Maybe something upstream has changed.
It is not reproduceable by myside, but per experience there are a few things you can try:
Put your project in a short path like "C:\".
Try a new blank project, see if the error occors.
If none of the above works, you can try reinstalling Xamarin in your VS.
This was solved due to my not linking a static resource that was declared in the xaml

ACR Reactive BluetoothLE Plugin Invalid State when starting server

I am building an iOS app with Xamarin and MvvmCross the required the use of Bluetooth LE. I am trying to use this plugin:
https://github.com/aritchie/bluetoothle
Here is my code:
var server = CrossBleAdapter.Current.CreateGattServer();
await server.Start(new AdvertisementData()); // throws exception
It throws an exception when trying to start the server:
{System.ArgumentException: Invalid State - Unknown at
Plugin.BluetoothLE.Server.GattServer.Start
(Plugin.BluetoothLE.Server.AdvertisementData adData) [0x0005f] in
<4281c4bd57f24525b20baae1afdf610b>:0
Apparently this plugin is easy to use so I must be missing something obvious?
That Exception indicates that the hardware is in invalid or initializing state and can be seen here: https://github.com/aritchie/bluetoothle/blob/master/Plugin.BluetoothLE.Apple.Shared/Server/GattServer.cs#L74
if (this.manager.State != CBPeripheralManagerState.PoweredOn)
throw new ArgumentException("Invalid State - " + this.manager.State);
I believe this is a bug in the code as it does not wait for the delegate to signal that the State has changed.
I found a solution. Instead of placing the code in my Core project, I placed it inside the iOS project itself, in a ViewDidAppear function, and placed a global variable in my UIViewController class:
private IGattServer server = CrossBleAdapter.Current.CreateGattServer();
I think you need to access the adapter with the appropriate thread, or at the appropriate time (after other initialization), hence why it was crashing before. I couldn't find an appropriate place to put this in my Core project, so I'm not sure if I have to put this code in each platform. Anyhow here's a solution for anyone else with this problem.

How to use new database instance of each MSTest unit test run

I'm using MSTest under Visual Studio 2010 to test an ASP.NET MVC 3 project. I have a SQL Express 2005 DB that I'd like it to use and I want a fresh instance of the DB every time, copied from a template I've included in the project. Pretty standard requirements, I would have though, but I can't get this to work.
I've created a .testsettings file which enables deployment and my connection string looks like this:
<add name="MyDb" connectionString="Data Source=.\SQLEXPRESS2005;Database=MyDbTest;AttachDBFilename=|DataDirectory|MyDbTest.mdf;User Instance=true;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
The test runs OK the first time, but after that it fails with errors like this:
Test method ... threw exception: System.Data.DataException: An exception occurred while initializing the database. See the InnerException for details. ---> System.Data.EntityException: The underlying provider failed on Open.
---> System.Data.SqlClient.SqlException: Database '...\bin\Debug\MyDbTest.mdf' already exists. Choose a different database name. Cannot attach the file '...\Out\MyDbTest.mdf' as database 'MyDbTest'.
The accepted answer in this MSDN thead says to remove the "Database=" connection string parameter. However, if I do that it fails with this error:
Test method ... threw exception:
System.InvalidOperationException: Unable to complete operation. The supplied SqlConnection does not specify an initial catalog.
How do I get this to work?
So far I've come up with a hack to change the DB name at runtime, at test assembly initialization time. This requires a further hack - using Reflection to enable modifying the configuration at runtime (thanks to David Gardiner).
[TestClass]
public static class TestHelper
{
[AssemblyInitialize]
public static void AssemblyInit(TestContext context)
{
RandomizeDbName();
}
private static void RandomizeDbName()
{
// Get the DB connection string setting
var connStringSetting = ConfigurationManager.ConnectionStrings["TheDbSetting"];
// Hack it using Reflection to make it writeable
var readOnlyField = typeof(ConfigurationElement).GetField("_bReadOnly",
BindingFlags.Instance | BindingFlags.NonPublic);
readOnlyField.SetValue(connStringSetting, false);
// Randomize the DB name, so that SQL Express doesn't complain that it's already in use
connStringSetting.ConnectionString = connStringSetting.ConnectionString.Replace(
"Database=MyTestDb", "Database=MyTestDb_" + new Random().Next());
}
}
Edit: It's actually even a bit worse than this: I'm having to call TestHelper.RandomizeDbName() at the start of every test that requires a fresh DB, otherwise it gets data left over from previous tests.

How do I use AutofacWebTypesModule to Resolve HttpServerUtilityBase

I have the following registrations
builder.RegisterModule(new AutofacWebTypesModule());
builder.Register<MyType>(ctx =>
{
var server = ctx.Resolve<HttpServerUtilityBase>();
...
});
When I try to resolve MyType via a constructor on an Controller, I get the following exception. What am I doing wrong?
Autofac.Core.DependencyResolutionException
was unhandled by user code
Message=No scope matching the
expression
'value(Autofac.Builder.RegistrationBuilder`3+<>c__DisplayClass0[System.Web.HttpServerUtilityBase,Autofac.Builder.SimpleActivatorData,Autofac.Builder.SingleRegistrationStyle]).lifetimeScopeTag.Equals(scope.Tag)'
is visible from the scope in which the
instance was requested.
Yikes - that error message has gone all wrong :)
The problem is most likely that you're trying to resolve MyType directly from the container (as opposed to the DependencyResolver or else you're taking a dependency on it from a singleton. The HttpServerUtilityBase component can only be used in the context of a web request.
Trying to resolve it from Applicaiton_Start will also fail in IIS7 integrated pipeline mode.
HTH!
Nick

Resources