12.02 Auxiliary C# Classes (XAMARIN)
-
Before generating the user interface for the very first View, all auxiliary interfaces, enums, helper classes, services, custom user controls must be in place and ready for use. The list of auxiliary files includes "Home", "Page not found", "Access Denied", "Paginator" user controls, global settings service, declaration of some global routed events and routed commands and so on.
-
It’s time to note that the order of generated files is extremely important. For instance, some classes may reference others. It means that referenced files must be generated before referencing files. And this is why CS2WPF Forms project file is used by the Wizards. The information about each generated file (file type, file name, file place and so on) is saved into CS2WPF Forms project file.
-
The second point relates to script types. All scripts are divided into two large sets:
- The first one consists of the context level scripts. These scripts are used to generate interfaces, classes, services that are used across the Views and application level components.
- The second set consists of the View level scripts. They are scripts that are used to generate the code for the given view. For instance, Edit form for one View is not applicable for another one because of captions, validations and so on.
-
These two large sets are organized as follows:
- Scripts with a range of 00000-00999 are context level scripts.
- Scripts with a range of 01000-99999 are view level scripts
-
To Generate AUXILIARY C# classes
- Run Visual Studio and Open “XamarinDemo” solution
- Step 1
- Right click "CommonInterfacesClassLibrary"-project node and select "Wpf Form Wizard"-menu
- Click "Next"-button
- Step 2
- Select "Dm02Context"-project
- Select "LitDbContext"-DbContext
- Click "Next"-button
- Step 3
- Select "==context==" in the combo
- Click "Next"-button
- Step 4
- Click "batch processing"-button
- Step 5
- Select "00000-ContextLevelCommonInterfacesBatch.Xamarin.json"-item
- Click "Start"-button
- After generation finished make sure that "Error"-panel is empty
- Close Wizard's dialogs
- Rebuild "ModelInterfacesClassLibrary"-project
- Repeat steps 1-5 for "CommonServicesPrismModule"-project and "00010-ContextLevelCommonServicesModuleBatch.Xamarin.json"
- Repeat steps 1-5 for "CommonCustomControlLibrary"-project and "00020-ContextLevelCustomControlLibraryBatch.Xamarin.json"
- Repeat steps 1-5 for "CommonUserControlLibrary"-project and "00030-ContextLevelCommonUserControlLibraryBatch.Xamarin.json"
- Repeat steps 1-5 for "CommonServicesPrismModule"-project and "00040-ContextLevelCommonServicesModuleBatch.Xamarin.json"
- Repeat steps 1-5 for "PrismDemoApp"-project and "00050-ContextLevelPrismAppBatch.Xamarin.json"
- Repeat steps 1-5 for "PrismDemoApp.Android"-project and "00060-ContextLevelPrismAppBatch.Xamarin.Android.json"
- Repeat steps 1-5 for "PrismDemoApp.iOS"-project and "00060-ContextLevelPrismAppBatch.Xamarin.iOS.json"
- Repeat steps 1-5 for "PrismDemoApp.UWP"-project and "00060-ContextLevelPrismAppBatch.Xamarin.UWP.json"
Open the "CommonServicesPrismModuleModule.cs"-file of CommonServicesPrismModule-project and and two lines of code into the body of "RegisterTypes()"-method. Make sure that "RegisterTypes()"-method is as follows
public void RegisterTypes(IContainerRegistry containerRegistry)
{
//these two lines are added
//////////////////
CommonInterfacesClassLibrary.AppGlblSettingsSrvc.IAppGlblSettingsService s = new AppGlblSettingsSrvc.AppGlblSettingsService();
containerRegistry.RegisterInstance<CommonInterfacesClassLibrary.AppGlblSettingsSrvc.IAppGlblSettingsService>(s);
//////////////////
containerRegistry.Register<CommonInterfacesClassLibrary.AppGlblLoginSrvc.IAppGlblLoginService, CommonServicesPrismModule.AppGlblLoginSrvc.AppGlblLoginService>();
containerRegistry.RegisterDialog<CommonServicesPrismModule.UserControls.ColumnSelectorDlgUserControl, CommonServicesPrismModule.ViewModels.ColumnSelectorDlgViewModel>("ColumnSelectorDlg");
containerRegistry.RegisterDialog<CommonServicesPrismModule.UserControls.MessageDlgUserControl, CommonServicesPrismModule.ViewModels.MessageDlgViewModel>("MessageDlg");
Prism.Mvvm.ViewModelLocationProvider.Register<CommonServicesPrismModule.Views.AccessDeniedPage, CommonServicesPrismModule.ViewModels.AccessDeniedPageViewModel>();
containerRegistry.RegisterForNavigation<CommonServicesPrismModule.Views.AccessDeniedPage, CommonServicesPrismModule.ViewModels.AccessDeniedPageViewModel>("AccessDeniedPage");
Prism.Mvvm.ViewModelLocationProvider.Register<CommonServicesPrismModule.UserControls.AccessDeniedUserControl, CommonServicesPrismModule.ViewModels.AccessDeniedViewModel>();
containerRegistry.RegisterForRegionNavigation<CommonServicesPrismModule.UserControls.AccessDeniedUserControl, CommonServicesPrismModule.ViewModels.AccessDeniedViewModel>("AccessDeniedUserControl");
containerRegistry.Register<Xamarin.Forms.ContentView, CommonServicesPrismModule.UserControls.AccessDeniedUserControl>("AccessDeniedUserControl");
Prism.Mvvm.ViewModelLocationProvider.Register<CommonServicesPrismModule.Views.PageNotFoundPage, CommonServicesPrismModule.ViewModels.PageNotFoundPageViewModel>();
containerRegistry.RegisterForNavigation<CommonServicesPrismModule.Views.PageNotFoundPage, CommonServicesPrismModule.ViewModels.PageNotFoundPageViewModel>("PageNotFoundPage");
Prism.Mvvm.ViewModelLocationProvider.Register<CommonServicesPrismModule.UserControls.PageNotFoundUserControl, CommonServicesPrismModule.ViewModels.PageNotFoundViewModel>();
containerRegistry.RegisterForRegionNavigation<CommonServicesPrismModule.UserControls.PageNotFoundUserControl, CommonServicesPrismModule.ViewModels.PageNotFoundViewModel>("PageNotFoundUserControl");
containerRegistry.Register<Xamarin.Forms.ContentView, CommonServicesPrismModule.UserControls.PageNotFoundUserControl>("PageNotFoundUserControl");
Prism.Mvvm.ViewModelLocationProvider.Register<CommonServicesPrismModule.Views.HomePage, CommonServicesPrismModule.ViewModels.HomePageViewModel>();
containerRegistry.RegisterForNavigation<CommonServicesPrismModule.Views.HomePage, CommonServicesPrismModule.ViewModels.HomePageViewModel>("HomePage");
Prism.Mvvm.ViewModelLocationProvider.Register<CommonServicesPrismModule.Views.RegisterUserPage, CommonServicesPrismModule.ViewModels.RegisterUserPageViewModel>();
containerRegistry.RegisterForNavigation<CommonServicesPrismModule.Views.RegisterUserPage, CommonServicesPrismModule.ViewModels.RegisterUserPageViewModel>("RegisterUserPage");
Prism.Mvvm.ViewModelLocationProvider.Register<CommonServicesPrismModule.Views.LoginUserPage, CommonServicesPrismModule.ViewModels.LoginUserPageViewModel>();
containerRegistry.RegisterForNavigation<CommonServicesPrismModule.Views.LoginUserPage, CommonServicesPrismModule.ViewModels.LoginUserPageViewModel>("LoginUserPage");
Prism.Mvvm.ViewModelLocationProvider.Register<CommonServicesPrismModule.Views.LogoutUserPage, CommonServicesPrismModule.ViewModels.LogoutUserPageViewModel>();
containerRegistry.RegisterForNavigation<CommonServicesPrismModule.Views.LogoutUserPage, CommonServicesPrismModule.ViewModels.LogoutUserPageViewModel>("LogoutUserPage");
Prism.Mvvm.ViewModelLocationProvider.Register<CommonServicesPrismModule.Views.ChngpswdUserPage, CommonServicesPrismModule.ViewModels.ChngpswdUserPageViewModel>();
containerRegistry.RegisterForNavigation<CommonServicesPrismModule.Views.ChngpswdUserPage, CommonServicesPrismModule.ViewModels.ChngpswdUserPageViewModel>("ChngpswdUserPage");
}
Open "App.xaml.cs"-file of PrismDemoApp-project and modify "ConfigureModuleCatalog()" method as follows
using Prism;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions.Adapters;
using Xamarin.Forms;
using Xamarin.Essentials.Interfaces;
using Xamarin.Essentials.Implementation;
using PrismDemoApp.Views;
using PrismDemoApp.ViewModels;
using CommonUserControlLibrary.UserControls;
using PrismDemoApp.Classes;
using CommonServicesPrismModule;
using ModelServicesPrismModule;
using FeatureServicesPrismModule;
namespace PrismDemoApp {
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{
public App(IPlatformInitializer initializer)
: base(initializer)
{
}
protected override async void OnInitialized()
{
InitializeComponent();
await NavigationService.NavigateAsync($"/MainFlyoutPage/NavigationPage/HomePage");
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterRegionServices(configureAdapters: OnconfigureAdapters);
containerRegistry.RegisterSingleton<IAppInfo, AppInfoImplementation>();
containerRegistry.RegisterForNavigation<NavigationPage>();
containerRegistry.RegisterForNavigation<MainFlyoutPage, MainFlyoutPageViewModel>();
}
private void OnconfigureAdapters(RegionAdapterMappings obj)
{
obj.RegisterMapping<ProxyUserControl, ProxyUserControlRegionAdapter>();
}
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
moduleCatalog.AddModule<CommonServicesPrismModuleModule>();
//////////////////////////////////////////
// these two lines are added to the method
moduleCatalog.AddModule<ModelServicesPrismModuleModule>();
moduleCatalog.AddModule<FeatureServicesPrismModuleModule>();
//////////////////////////////////////////
}
}
}
Open "Configuration Manager"
Add "Build" and "Deploy" items as shown below
Rebuild all front end projects and run PrismDemoApp.
Click "Register"-menu item. Click "Home"-navigation menu again.
Rebuild all front end projects and run PrismDemoApp.
Click Dm04WebApp root node to get project properties visible. Copy SSL URL into clipboard.
Open "CommonServicesPrismModule/AppGlblSettingsSrvc/AppGlblSettingsService.cs"-file of the CommonServicesPrismModule-project. Modify GetWebApiPrefix() and GetSecurityWebApiPrefix() by resetting URLs.
...
public string GetWebApiPrefix(string ViewName)
{
string rslt = "";
if(!string.IsNullOrEmpty(ViewName))
{
rslt = "https://localhost:44358/";
}
return rslt;
}
public string GetSecurityWebApiPrefix()
{
return "https://localhost:44358/";
}
...
Install MS SQL Server anywhere in your network or virtual environment. Get "sa"-password, network name of the SQL server and the port (if necessary). Open Web.config-file of Dm04WebApp-project and modify "DefaultConnection"-settings. Here is example:
...
<connectionStrings>
<add name="DefaultConnection"
connectionString="Data Source=SVR2016SQL2017;Initial Catalog=AspNetDbWebApplicationXamarinDemoSecurity;Persist Security Info=True;User ID=sa;Password=sa_PASSWORD_HERE"
providerName="System.Data.SqlClient" />
</connectionStrings>
...
Note: You will have different "Data Source"-property in your development invoronment.
The front and back ends are ready to register user, login, logout, change password operations.
- Rebuild CommonServicesPrismModule-project
- Run Dm04WebApp.UWP (Dm04WebApp will be started automatically)
- Click "Register User"-menu
- enter [User name]="testuser@gmail.com"
- enter [Password]="Qq?1234"
- enter [Confirm password]="Qq?1234"
- Click Ok
As a result: Error message will be shown
Stop debuging and copy the second URL "http://localhost:52157/" into "GetWebApiPrefix" and "GetSecurityWebApiPrefix"-methods. The second URL is not "https"-address.
...
public string GetWebApiPrefix(string ViewName)
{
string rslt = "";
if(!string.IsNullOrEmpty(ViewName))
{
rslt = "http://localhost:52157/";
}
return rslt;
}
public string GetSecurityWebApiPrefix()
{
return "http://localhost:52157/";
}
...
- Run Dm04WebApp.UWP (Dm04WebApp will be started automatically)
- Click "Register User"-menu
- enter [User name]="testuser@gmail.com"
- enter [Password]="Qq?1234"
- enter [Confirm password]="Qq?1234"
- Click Ok
- after susccess you will be redirected to the "Home"-page
With "SQL Management studion" execute thee following SQL-script:
SELECT * FROM [AspNetDbWebApplicationXamarinDemoSecurity].[dbo].[AspNetUsers]
The result is on the picture below
For now Login with PrismDemoApp and "testuser@gmail.com" and password "Qq?1234". After login you will be redirected to the "Home"-page without exceptions. (Nobody knows where the best place to show logined user name. This is why the username is not shown).
It is know, that virtual machines are used for the emulators. So, "Localhost" will not be useful in all cases.
- Run Dm04WebApp.Android (Dm04WebApp will be started automatically)
- enter [User name]="androidTest@gmail.com"
- enter [Password]="Qq?1234"
- enter [Confirm password]="Qq?1234"
- Click Ok
We expect this result. We should use IP-addresses.
- At first, we modified "AppGlblSettingsService.cs"-file of the CommonServicesPrismModule-project
...
public string GetWebApiPrefix(string ViewName)
{
string rslt = "";
if(!string.IsNullOrEmpty(ViewName))
{
if (Device.RuntimePlatform == Device.Android)
{
rslt = "http://10.0.2.2:52157/";
}
else
{
return "http://localhost:52157/";
}
}
return rslt;
}
public string GetSecurityWebApiPrefix()
{
if (Device.RuntimePlatform == Device.Android)
{
return "http://10.0.2.2:52157/"; //
} else
{
return "http://localhost:52157/";
}
}
...
- At second, we added one additional binding to applicationhost.config-file:
<bindings>
<binding protocol="https" bindingInformation="*:44358:localhost" />
<binding protocol="http" bindingInformation="*:52157:localhost" />
<binding protocol="http" bindingInformation="*:52157:127.0.0.1" />
</bindings>
- Run Dm04WebApp only
- check if all bindings are active
- on the picture below it is shown that we have only one binding
- open the folder
%TEMP%\iisexpress
- open very last log-file
- Rebuild Dm04WebApp and start Dm04WebApp again. All is the same.
- Restart Visual Studio as ADMIN
- Rebuild and start Dm04WebApp.
- check if all bindings are active
We just detected the direction of how to set up the development environment. To run Visual Studion as Admin is not a very good idea. Run PowerShell as admin and execute two commands.
netsh http add urlacl url=http://127.0.0.1:52157/ user=everyone
netsh http add urlacl url=http://localhost:52157/ user=everyone
Restart Visual Studion (do not use as Admin). Start Dm04WebApp. Make sure all bindings are active.
- Run Dm04WebApp.Android (Dm04WebApp will be started automatically)
- Click "Register User"-menu item
- enter [User name]="androidTest@gmail.com"
- enter [Password]="Qq?1234"
- enter [Confirm password]="Qq?1234"
- Click Ok
- here is a result
- When you start development (i.e. generate application code) and test the result, you may receive the following error:
- To fix the issue, make sure that
- "Newtonsoft.Json"-package is identical on the server side and on the client side of the project
-
Do the same for "EntityFramework"-package on the server side
-
Rebuild server side projects. Here is a result: