Upload
vandat
View
252
Download
4
Embed Size (px)
Citation preview
Building a mobile enterprise application with Xamarin.Forms,
Docker, MVVM and .NET CoreGill Cleeren
@gillcleeren – www.snowball.be
Kliant provides hands-on in-depth advanced software development training that is customized/tailored to your specific requirements
Our instructors are experienced developers, renowned subject matter experts and respected authors
Your contact: Eric Swanson – [email protected]
Kliant. Nice to meet you.
LA – Atlanta - London
Upcoming virtual courses
• Developing cross-platform apps with C# using Xamarin• 2 Day
• March 1-2
• Mastering ASP.NET Core 2 MVC• 2 Day
• March 26-27
Some seats still available!
Agenda
• Overall application structure
• The Xamarin application architecture• MVVM• Dependency Injection• Loose-coupled Messaging• Navigation• Service communication• Testing
• Backend architecture• .NET Core-based Microservices• Docker
The Solution Structure
Backend in Docker hostClient apps
Xamarin.Formsmobile app
HTML web front-end
SPA
Microservice 1Product catalog
Microservice 2Ordering
Microservice 3Identity
MVC app
DEMOLooking at the Solution Structure & the Finished Application
The Xamarin application architecture
MVVM
MVVM
• Architectural pattern
• Based on data binding and commanding
• Popular for testable and maintainable XAML applications
What we all did when we were young…
Write code in code-behind… Lots of it.
Data Model
View
XAML
Code-BehindEvent Handlers
Writing testable code however, is becoming the norm. Finally. Courtesy of MVVM.
Data Model
View
XAML
Code-Behind
View Model
State + Operations
Change notification
Data-binding and commands
Benefits of MVVM
• Testable
• Developers and designers can work independently
• A new XAML view can be added on top of the view models without problems
• Changes can be made in view model without risking issues with the model
User interface
Window, Page or user control
Simple
No business logic
Functionalities of the View
View
MyPage.xaml
MyPage.xaml.cs
Sample View Code
<Entry Text="{Binding UserName.Value, Mode=TwoWay}"> </Entry>
<LabelText="{Binding UserName.Errors,Converter={StaticResource FirstValidationErrorConverter}" />
<ListViewIsVisible="{Binding Campaigns.Count, Converter={StaticResource
CountToBoolConverter}}"ItemsSource="{Binding Campaigns}"
Glue between view and Model
Expose state and operations
Testable
No UI elements
Functionalities of the View Model
View Model
Sample View Model Code
public class LoginViewModel : INotifyPropertyChanged{public string UserName{ get; set; }
public string Password{ get; set; }
public ICommand SignInCommand=> new Command(async () => await SignInAsync());
}
ModelData model - services
Return data
Functionalities of the Model
DEMOLooking at the Model in the application
Responding to changes in the (view) model
• Handled through INotifyPropertyChanged interface
• PropertyChanged raised for changes of view model or model property value changes• (View)Model property changes
• Calculated properties
• Raise event at the end of a method that makes changes to the property value
• Don’t raise PropertyChanged when the value didn’t change
• Don’t raise PropertyChanged from the constructor
• Don’t raise PropertyChanged in a loop
BindableObject
public abstract class ExtendedBindableObject : BindableObject{
public void RaisePropertyChanged<T>(Expression<Func<T>> property){
var name = GetMemberInfo(property).Name;OnPropertyChanged(name);
}
private MemberInfo GetMemberInfo(Expression expression){
...}
}
DEMOLooking at the ViewModels and the Views
Commanding
• Action is defined in one place and can be called from multiple places in the UI
• Available through ICommandinterface
• Defines Execute() and CanExecute()
• Can create our own or use built-in commands
The ICommand Interface
public interface ICommand{
event EventHandler CanExecuteChanged;bool CanExecute(object parameter);void Execute(object parameter);
}
Exposing Operations on the View Model
public class LoginViewModel : ViewModelBase
{
public ICommand SignInCommand => new Command(async () => await SignInAsync());
public ICommand RegisterCommand => new Command(Register);
}
Binding Your Commands in the View
<ToolbarItem
Command="{Binding SettingsCommand}"
Text="Settings">
Behaviors
• Command property available only on ButtonBase-derived controls
• Other controls and interactions only possible through “behaviours”
• Use of an attached behaviour
• Use of a Xamarin.Formsbehaviour
public class EventToCommandBehavior : BindableBehavior<View>{
protected override void OnAttachedTo(View visualElement){ ... }
}
EventToCommandBehavior
Using EventToCommandBehavior
<ListViewItemsSource="{Binding Orders}"><ListView.Behaviors>
<behaviors:EventToCommandBehaviorEventName="ItemTapped"Command="{Binding OrderDetailCommand}"EventArgsConverter="{StaticResource ItemTappedEventArgsConverter}" />
</ListView.Behaviors></ListView>
Using TapGestureRecognizer
<StackLayout ><Label Text="SETTINGS"/><StackLayout.GestureRecognizers><TapGestureRecognizer
Command="{Binding SettingsCommand}"NumberOfTapsRequired="1" />
</StackLayout.GestureRecognizers></StackLayout>
DEMOCommanding Done Right
Who Knows Who?
View ModelView Model
View Model-FirstView-First
Linking the View and the View Model
View-First (from XAML)
<ContentPage><ContentPage.BindingContext>
<local:LoginViewModel/></ContentPage.BindingContext>
</ContentPage>
View First (from code)
public LoginView(){
InitializeComponent();BindingContext = new LoginViewModel();
}
The View Model Locator
ViewModelLocator
View Model 1
View Model 2
View Model n
View 1
View 2
View n
DEMOThe ViewModel Locator
Dependency Injection
Dependency Injection
• Type of inversion of control (IoC)
• Another class is responsible for obtaining the required dependency
• Results in more loose coupling
• Container handles instantiation as well as lifetime of objects
• Autofac is commonly used
• Many others exist
Dependency Injection
IContainerProfileViewModel OrderService
IOrderService
Dependency Injection
public class ProfileViewModel : ViewModelBase{
private IOrderService _orderService;
public ProfileViewModel(IOrderService orderService){_orderService = orderService;
}}
Advantages of using Dependency Injection• Better testability through easy
way of using mock versions
• Higher maintainability by making it easy to add new classes• Central location
• Dependencies don’t affect the class that uses them
• Classes don’t need to manage their dependencies• It’s handled for them
• They add complexity• Not always a good idea for
small apps…
Container registration
• Happens at application startup
builder.RegisterType<NavigationService>().As<INavigationService>().SingleInstance();builder.RegisterType<DialogService>().As<IDialogService>();
Resolving dependencies
• If the requested type can’t be found, an exception is thrown
• If a type is requested that registered as singleton, we always will get back the same instance• A new instance will only be created once, the first time it’s requested
• Otherwise, a new instance will always be returned
NavigationService = ViewModelLocator.Resolve<INavigationService>();
DEMOWorking with Dependency Injection
Loose-coupled Messaging
View Model communication
View Model
View Model
View Model View Model
View Model
View Model
View Model View Model
Messaging Center built-in in Xamarin.Forms
Data Model
View
XAML
Code-Behind
Data Model
View
XAML
Code-Behind
Message
View Model
State + OperationsView Model
State + Operations
View
XAML
Code-Behind
MessageMessaging Center
(XF)
View Model
State + Operations
Publish messages
Subscribe to messages
Messaging Center
• Implements pub-sub model for us already
• Built-in in Xamarin.Forms
• Multicast supported
• Based on strings (not always perfect)
DEMOWorking with Messages and the Messaging Center
Navigation
Navigation and MVVM
• Navigation isn’t always easy to include in an MVVM scenario• No tight-coupling can be
introduced• Who is responsible for
navigation? View Model? View?
• How can we pass parameters during navigation?
• Xamarin.Forms comes with INavigation interface• Will be wrapped as it’s too
basic for real-life scenarios
Our Own NavigationService
• Must be registered in the Dependency Injection system
public interface INavigationService{ViewModelBase PreviousPageViewModel { get; }
Task InitializeAsync();
Task NavigateToAsync<TViewModel>() where TViewModel : ViewModelBase;
Task NavigateToAsync<TViewModel>(object parameter) where TViewModel : ViewModelBase;
Task RemoveLastFromBackStackAsync();
Task RemoveBackStackAsync();}
DEMOAdding Navigation
Service communication
Take some REST
• REST: Representational State Transfer
• Based on open HTTP standards
• Open for all types of applications
• Works with Resources
• We’ll send requests to access these resources
• URI and HTTP method are used for this
• Results in HTTP Status code
• 200, 404… based on result of request
Communicating with a REST API
• Apps will typically use services for making the data request• Are responsible for communication with the actual API
• Controllers on API microservices return DTOs
• Are transferred to the application
• App can use HttpClient class• Works with JSON
• Returns HttpResponseMessage after receiving a request
• Can then be read and parsed • Json.NET
Loading data from the service
public override async Task InitializeAsync(object navigationData){IsBusy = true;Products = await _productsService.GetCatalogAsync();Brands = await _productsService.GetCatalogBrandAsync();Types = await _productsService.GetCatalogTypeAsync();IsBusy = false;
}
Using the Data Servicepublic async Task<ObservableCollection<CatalogItem>> GetCatalogAsync(){UriBuilder builder = new UriBuilder(GlobalSetting.Instance.CatalogEndpoint);
builder.Path = "api/v1/catalog/items";string uri = builder.ToString();
CatalogRoot catalog = await _requestProvider.GetAsync<CatalogRoot>(uri);
if (catalog?.Data != null){ServicesHelper.FixCatalogItemPictureUri(catalog?.Data);
return catalog?.Data.ToObservableCollection();}elsereturn new ObservableCollection<CatalogItem>();
}
Using the RequestProvider
public async Task<TResult> GetAsync<TResult>(string uri, string token = ""){HttpClient httpClient = CreateHttpClient(token);HttpResponseMessage response = await httpClient.GetAsync(uri);
await HandleResponse(response);string serialized = await response.Content.ReadAsStringAsync();
TResult result = await Task.Run(() => JsonConvert.DeserializeObject<TResult>(serialized, _serializerSettings));
return result;}
Action in the Controller in the Microservice[HttpGet][Route("[action]")]public async Task<IActionResult> Items([FromQuery]int pageSize = 10, [FromQuery]intpageIndex = 0){var totalItems = await _catalogContext.CatalogItems.LongCountAsync();
var itemsOnPage = await _catalogContext.CatalogItems.OrderBy(c => c.Name).Skip(pageSize * pageIndex).Take(pageSize).ToListAsync();
itemsOnPage = ChangeUriPlaceholder(itemsOnPage);
var model = new PaginatedItemsViewModel<CatalogItem>(pageIndex, pageSize, totalItems, itemsOnPage);
return Ok(model);}
DEMOAccessing Remote Data
Unit Testing
Testing is REALLY needed
• Different devices
• Network
• Performance
• Different resolutions
• Different OS versions
A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about the behaviorof that unit of work.From The Art of Unit Testing, Roy Osherove
Unit testing
• Block of code that needs to be tested
• Public API
• Isolated
• Fast
• Refactor with confidence
• Automated
• Independent• Dependency injection will help here
IOrderService
OrderServiceMockOrderService
Why we need unit tests?
• Find bugs
• No fear to break something when making changes
• Improve code quality
• Code documentation
Structure of a unit test
• Arrange
• Act
• Assert
DEMOUnit Testing
Backend architecture
ASP.NET Core
.NET Core
“.NET Core is a general purpose development platform maintained by Microsoft and the .NET community on GitHub. It is cross-platform, supporting Windows, macOS and Linux, and can be used in device,
cloud, and embedded/IoT scenarios.”
source: https://docs.microsoft.com/en-us/dotnet/articles/core
ASP.NET Core
“ASP.NET Core is a new open-source and cross-platform framework for building modern cloud based internet connected applications, such as
web apps, IoT apps and mobile backends.”
source: https://docs.microsoft.com/en-us/aspnet/core
ASP.NET Core
• Built on top of .NET Core
• Lightweight
• Cross-platform• Windows, Mac & Linux
Easy in combination with Docker and Microservices
What does ASP.NET Core bring us then?
• Unification between MVC and Web API
• Dependency Injection
• Modular HTTP request pipeline
• Based on NuGet
• Cloud-ready
• IIS or self-host
• Open source
• Community focus
• Cross-platform
• New tooling
• Better integration of client-side frameworks
• Command-line support
Containerized Microservices
Monoliths
• Client-server often results in tiered applications
• Specific technology used per tier
• Known as monolithic applications
• Often have tight coupling between components in each tier
• Components can’t be scaled easily
• Testing individual components might also be hard
Monoliths
• Not being able to scale can be issue for cloud readiness
• All layers typically are required
• Scaling is cloning the entire application onto multiple machines
Monolithic applications
Enter microservices
• Microservices are easier for deployment and development• Better agility • Better combination with cloud
• App will be decomposed into several components• Components together deliver app functionality
• Microservice = small app, independent concern• Have contracts to communicate with other services
• Typical microservices• Shopping cart• Payment system• Inventory system
Enter microservices
• Can scale out independently • If an area requires more processing power, can be scaled out separately
• Other parts can remain the same
• Scale-out can be instantaneous• Web front-end for handling more
incoming traffic
Enter microservices
• Microservices manage their own data• Locally on the server on which they run
• Avoid network overhead
• Faster for processing
• Even eliminate need for caching
• Support for independent updates• Faster evolution
• Rolling updates, onto subset of instances of single service support rollback
Benefits of using microservices• Small
• Evolve easily
• Scale-out independently
• Isolate issues to the faulty microservice
• Can use latest and greatest
• Not constrained to using older technologies
Disadvantages of microservices• Partitioning a real application is hard
• Complex
• Intercommunication between services
• Eventual consistency
• Atomic transactions often not supported
• Deployment (initial) might be harder
• Direct client-to-microservice communication might not be a good idea
DEMOLooking at the Microservices
“Containerization is an approach to software development in which an application and its versioned set of dependencies, plus its environment configuration abstracted as deployment manifest files, are packaged together as a container image, tested as a unit, and deployed to a host operating system”
Adding containers to the mix• Container is isolated, resource
controlled and portable operating environment
• Applications in containers run without touching resources of host or other containers
• Acts like a VM or physical machine
• Work great in combination with microservices
• Docker is most commonly used approach here
What’s a container really?
• Container runs an operating system
• Contains file system
• Can be accessed over the network like a real machine/VM
• Contain the application (and dependencies)
• In general, require less resources to run than regular VMs
• Allow for easy and fast scale-up by adding new containers
Adding containers to the mix
Using Docker to host the microservices
• Each container hosts a separate part of the application• Single area of functionality
• Each microservice has its own database• Allows for full decoupling
• Consistency is eventual
• Can be improved using application events• Service bus
Microservice 1Product catalog
Microservice 2Ordering
Microservice 3Identity
DEMOContainerization
Summary
• MVVM is the go-to standard for building enterprise-level Xamarin.Forms apps
• .NET Core is a good choice for building microservices
• Docker helps with deployment of microservices
Thanks!
Building a mobile enterprise application with Xamarin.Forms,
Docker, MVVM and .NET CoreGill Cleeren
@gillcleeren – www.snowball.be