Welcome to the sixth part of this article series on developing for a multitude of clients, in which we talk about strategies for code reuse and keeping costs in check. In the previous articles, we've looked into different ways of getting our code split up in modules, so they can be loaded on demand, and easily reused across different types of clients - thus cutting costs and saving on development time. However: up until now, we've focused on clients that were alike: a Silverlight web client, and a Silverlight Out of Browser client. In this article, we'll look into a different one: a Windows Phone client - in which code sharing isn't possible by default, as those apps are built against another version of the CLR.
In this article, we'll look into what we can reuse from the existing code base when creating a Windows Phone client. Interesting to notice here is that "being able to reuse code" doesn't mean "should reuse code".
What can we reuse from our previous applications and/or backend?
Of course, we've got some skill reuse: after all, Windows Phone development is Silverlight development. That said, there are other things to keep in mind here.
The first one: what do we want to offer to our end users with this mobile application? As stated in the first part of this article series, the general idea of having a mobile component to an already-existing application is that we do not want to offer the complete set of functionalities the full application has to the end user. We're building a way to extend his experience to on-the-road use, we're not building a replacement of the full application - for our business case to succeed, the end user should still have an incentive to use the full-blown application.
Second, there's the connection we're working with: you're typically running on an EDGE or 3G connection, meaning: slower than the Wi-Fi or networked connection used with the other Silverlight clients, and, depending on the plan the end user has with his phone company: potentially (exponentially) more expensive. This means that the amount of data transferred should be kept in mind at all times - and preferably as low as possible. We need to find a good trade-off between data transfer, speed and development time.
Third, there's the UI. When you're designing a Windows Phone application, you're designing for smaller screen estate, with touch-based input, and you'd want your application to feel like it conforms to the way Windows Phone apps typically look. This typically requires a different UI than our Silverlight clients. Microsoft has a great set of guidelines on Metro design, which you can read about here.
With all these things in mind, what can we reuse for our phone client? Obviously, we shouldn't reuse the Views, as they will deliver a sub-par user experience, almost by default (different screen estate, different input method). We shouldn't reuse our ViewModels: after all, they are, by convention at least, coupled to the corresponding Views, and designed for regular Silverlight clients - bandwidth considerations are different. And even if we would ignore that, some of the code in those ViewModels won't just recompile in a Windows Phone application: it's built on a different version of the CLR. One obvious example would be the way we'll access our services: working with a Domain Service from Windows Phone = working with the SOAP or REST (JSON) endpoints.
What can we reuse then?
- Existing skills
- Our backend services: the Authentication domain service, and the Employee Opportunity domain service.
- We can also reuse some common login and/or code, typically by transferring that code to a class library that can be referenced by the Silverlight app as well the Windows Phone app. As you might know, this isn't possible by default: Visual Studio disallows referencing assemblies that are built against a different version of the CLR, or (depending on what it's built against) will warn you about this. Luckily, there's a specific project template designed for this, the Portable Class Library.
Windows Phone client: the demo application case.
The general idea behind our new mobile client is that we want to provide our customers with parts of the functionality of the full application, not all of it. While it's technically possible, we're not trying to rebuild the complete application on the phone: it makes more sense to only provide those parts that are useful when on the road. Coincidently, that fits with the theme of this article series: when you're trying to keep costs in check, scope management is very important.
For the demo application, we're going to enable the user to log in to the app on the phone, get an overview of his opportunities, and look at the detail of them. An app like this contains everything we need for this series: reuse of the services, and sharing of some common logic. Note that if we were to build this app for real-life use, we might want to enable the user to edit/add new opportunities on the go as well.
There's a tremendous amount of resources available at SilverlightShow if you want to learn more about building Windows Phone applications.
Reusing the backend: consuming domain services from a Windows Phone application.
WCF RIA Services is a powerful framework for building Silverlight application: you get client-side change tracking, generation of client-side versions of your entities, validation, authentication/authorization, … When you try to use this in a Windows Phone application, you'll immediately notice this isn't possible in the way you're used to: you cannot reference the necessary WCF RIA Services assemblies in your Windows Phone application, you don't get client-side Domain Contexts corresponding to your domain services, … so - are we stuck?
No, we're not: domain services can be accessed from a Windows Phone application through a variety of endpoints: SOAP, REST and OData (read-only). For our application, we're going to reuse both domain services: the SalesAuthenticationService to log in, and the EmployeeOpportunityService to get data to the Windows Phone application.
The WCF RIA Services Toolkit contains all the necessary components to allow this - and the easiest way to add this is through NuGet. Locate the RIAServices.Endpoints package, and install it to the Dashboard ServiceHost. Installing this will add a few lines of code to the web.config file:
<domainServices>
<endpoints>
<add name="OData" type="System.ServiceModel.DomainServices.Hosting.ODataEndpointFactory,
System.ServiceModel.DomainServices.Hosting.OData,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add name="soap" type="Microsoft.ServiceModel.DomainServices.Hosting.SoapXmlEndpointFactory,
Microsoft.ServiceModel.DomainServices.Hosting,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add name="JSON" type="Microsoft.ServiceModel.DomainServices.Hosting.JsonEndpointFactory,
Microsoft.ServiceModel.DomainServices.Hosting,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</endpoints>
</domainServices>
We're going to use the soap endpoint. As you can see in the web.config file, it's the SoapXmlEndpointFactory that ensures the soap endpoint is created & accessible. To access a domain service through its soap endpoint, you can navigate to "namespace.classname", replacing the dots by dashes, and adding .svc to that url. However, in the second article of this series, we enabled better naming for our services: this makes it even easier to access the soap endpoints, as it's exactly the same URL as before: http://localhost/SalesDashboard.ServiceHost/EmployeeOpportunityService.svc?wsdl
Let's have a look at the WSDL, with these new endpoint factories in the web.config:
<wsdl:service name="EmployeeOpportunityDomainService">
<wsdl:port name="BasicHttpBinding_EmployeeOpportunityDomainServicesoap"
binding="tns:BasicHttpBinding_EmployeeOpportunityDomainServicesoap">
<soap:address location="http://localhost/SalesDashboard.ServiceHost/EmployeeOpportunityService.svc/soap"/>
</wsdl:port>
(note: the WSDL is much bigger than the excerpt above – this is the SOAP-related part)
As you can see, simply by adding the endpoint factories from the RIAServices.Endpoints package, our domain services are accessible through the SOAP endpoint. We're done with the server side for now.
How does a domain service work when exposed through a SOAP endpoint?
An important question remains: how does a domain service function when a client tries to access it through a SOAP endpoint?
- For each query method we've defined in our domain service, a corresponding method is generated in the proxy client, so we can load data from the domain service to the Windows Phone application.
- When the operation completes, we get a set of results through the completed events' arguments. This result object inherits QueryResult, and contains two properties that are interesting for us: RootResults and IncludedResults. RootResults contains the list of parent items returned by the domain service query method. IncludedResults contains possible child items, if you're returning those (as you know, you can include child entities to be sent over the wire with RIA Services by using the [Include] attribute in your metadata file)
- To submit data, you can create a list of ChangeSetEntry on the client, which you can pass to the proxy clients' SubmitChangesAsync method. Once this call reaches the server, the corresponding create, update or delete methods will be executed. This will recreate the change set on the server, entry by entry, after which they will be persisted to the data store (in our case, we're using the Entity Framework as backend store).
- The call to that method will return with a list of ChangeSetEntry: this will contain each persisted entry. You can use this list to check for problems when submitting, for ValidationErrors, ...
That is, in a nutshell, how the main functionalities of a domain service are exposed to our Windows Phone application: we've got all our query methods, we can get results including child results, we can create a change set in our Windows Phone app, and we can submit this change set back to our domain service.
What’s next?
In the next article, we’ll look at how we can consume the SOAP endpoints we’ve created from our Windows Phone application: we’ll look into authentication, and passing that authentication cookie to the domain service calls. Next to that, we’ll also look into how we can achieve some further code sharing through the use of a Portable Class Library.
Stay tuned! :-)
About the author
Kevin Dockx lives in Belgium and works at RealDolmen, one of Belgium's biggest ICT companies, where he is a technical specialist/project leader on .NET applications, mainly XAML-based, and a solution manager for Rich Applications (Windows 8 Metro, Silverlight, Windows Phone 7 Series, WPF, Surface, HTML5). His main focus lies on all things XAML, but he still keeps an eye on the new developments concerning other products from the Microsoft .NET (Web) Stack. As a XAML enthusiast, he's a regular speaker on various national and international events, like Microsoft Techdays in Belgium, Portugal & Finland, NDC2011, Community Day, ... Next to that, he also authored two Silverlight books at Packt Publishing, of which the most recent one is the Silverlight 5 Data and Services Cookbook, together with Gill Cleeren. His blog, which contains various tidbits on XAML, .NET, and the occasional rambling, can be found at http://blog.kevindockx.com/, and you can contact him on Twitter via @KevinDockx.