Pages - Menu

Friday, May 5, 2017

Numeric keyboard with "Done" button on iOS Xamarin.Forms


'Done' button on Numeric keyboard on iOS is a very popular clients request, but it does not appear out of the box. Luckily the solution is very easy (as usual), all we have to do is to extend 'Entry' control and to add a custom renderer:


As you can see all the 'magic' is happing in AddDoneButton() method. We create a toolbar and add a 'Done' UIBarButtonItem which will hide the keyboard and send a 'Completed' event back.

The solution is based on this thread and available as a gist on github.

Thursday, April 6, 2017

INotifyPropertyChange without boilerplate code in Xamarin.Forms

Implementing INotifyPropertyChange is pretty straightforward. Usually, you create a base ViewModel class which implements it and which usually contains RaisePropertyChanged method:

public abstract class BaseViewModel : INotifyPropertyChanged
{
    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(
        [CallerMemberNamestring propertyName = "")
    {
        PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(propertyName));
    }
    #endregion
}

Now you can extend the BaseViewModel and use it this way:
public class UserViewModel : BaseViewModel
{
    private string login;
    public string Login
    {
        get
        {
            return login;
        }
        set
        {
            if (login == value)
                return;

            login = value;
            RaisePropertyChanged();
        }
    }

    private string password;
    public string Password
    {
        get
        {
            return password;
        }
        set
        {
            if (password == value)
                return;

            password = value;
            RaisePropertyChanged();
        }
    }
}

For very small applications it can be a good enough approach, however, in bigger applications it turns into a lot of boring boilerplate code. Here is where NotifyPropertyChanged.Fody comes into play! With this nice package our code will turn into:

[ImplementPropertyChanged]
public abstract class BaseViewModel {}

public class UserViewModel : BaseViewModel
{
    public string Login { getset; }
    public string Password { getset; }
}

Easy as it is! I highly recommend to get familiar with the documentation as it contains a lot of useful information about more advanced flows. For example, if you need to RaisePropertyChange for dependent properties or to skip equality comparison.

Sunday, April 2, 2017

Though about optimisation of work with XAML in Xamarin.Forms

What is great about Xamarin.Forms? XAML of course! Especially if you are familiar with it from WPF / Silverlight times. However, the experience with XAML in Xamarin.Forms is totally different. Unfortunately, you will not have such a great intellisense, by default you will have to discover typos in XAML at runtime, no visual editor (yet) and without preview. I have been using VS 2017 on Windows and VS For Mac on macOS, in both cases problems listed above exists.

There are a lot of threads on stackoverflow about these problems and I am repeating myself, again and again, so I decided to write a post about it. I don't have a magic solution, just a few tricks and a though.

If you are already familiar with XAML and Xamarin.Forms and you don't care that much about intellisence you can turn on XAML compilation to catch the typos at compile time.
You can enable it at the assembly level, by adding the next line of code to your AssemblyInfo.cs:
[assembly: XamlCompilation(XamlCompilationOptions.Compile);
Or turn XAML compilation at the class level, just the next line above class declaration:
[XamlCompilation (XamlCompilationOptions.Compile)];
More detailed information can be found here.

FYI: If you set the BindingContext inside XAML you may meet this bug.

Remember that all you do in XAML is compiled to code in the end. That means that if the IDE is not working that great with XAML for Xamarin.Forms at this time, you can write everything in plain C#!
Sounds weird, however, all the problems listed above will be solved - except preview. But I find it attractive enough to try. Defining your UI layout in code behind will not violate any of MVVM principles as far as it's not going to include any business logic.

If you know any other tricks please share.
Have a nice week.

Sunday, March 26, 2017

UIDatePicker Countdown mode bug and solution in Xamarin.Forms

Problem

Show hh:mm:ss picker on iOS using Xamarin.Forms.

Goal

Extend Picker view in order to achieve the next result:

Solution

First I tried to keep it simple: to give up on seconds and use UIDatePicker in UIDatePickeCountDownMode. So the end result will look like this:
I achieved it by extending the DatePicker and it's DatePickerRenderer and changing the mode as described above. However, I discovered that 'datePickerValueChanged' is being called only on a second iteration with the values. The issue was successfully reproduced in Swift, so it's not a Xamarin bug. The Swift version can be found here.

After spending some time understanding the issue described above, I found an example on StackOverflow, thanks to Mathieu who shared his solution. His example was based on XLabs, so I removed the dependency and shared it with the community.
The code can be found on GitHub.


Tuesday, March 21, 2017

JSON.net Mastering enums

Problem

Legacy backend API endpoint returns JSON with units in an uncommon manner.
Instead of returning the measurement system "imperial" or "metric" it returns "kgs" or "lbs".

Goal

Using JSON.net deserialize & serialize "kgs" to "metric" and "lbs" to "imperial" in our front-end app.

Solution

The solution is pretty simple. We have to define an enum, with "EnumMember" attributes on each element and use "StringEnumConverter" as preferred JsonConvertor. Here is the full and working example:

using System;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace JSONnetEnums
{
    class Program
    {
        static void Main(string[] args)
        {
            var deserializedObj = 

                JsonConvert.DeserializeObject<Foo>("{\"Unit\":\"kgs\"}");
            Console.WriteLine(deserializedObj.Unit);
            // Output: Metric

            var serializedObj = 

                JsonConvert.SerializeObject(new Foo { Unit = Unit.Imperial });
            Console.WriteLine(serializedObj);
            // Output: {"Unit":"lbs"}
        }
    }

    class Foo
    {
        public Unit Unit { getset; }
    }

    [JsonConverter(typeof(StringEnumConverter))]
    enum Unit
    {
        [EnumMember(Value = "kgs")]
        Metric,
        [EnumMember(Value = "lbs")]
        Imperial
    }
}

Wednesday, March 15, 2017

Xamarin Forms SQLite-net PCL nuget package failing to install

Following Local Databases Xamarin guide in order to add SQLite database to a Xamarin Forms project I spent quite some time on adding the "SQLite.Net PCL" nuget package. It failed with the next message:

Could not install package 'System.Runtime.InteropServices.RuntimeInformation 4.0.0'. You are trying to install this package into a project that targets '.NETPortable,Version=v4.5,Profile=Profile111', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.

The solution is pretty easy, you just have to install "System.Runtime.InteropServices.RuntimeInformation" before installing "SQLite.Net PCL"  nuget package.

More details can be found here.

Tuesday, March 14, 2017

JSON.net snake case notation naming strategy

Communicating with backend in JSON can be challenging.
In case of C# model which by convention should be in CamelCase notation and backend which is using snake_notation we can easily solve the problem with Json.NET.

For example, we have the next model:

public class Model
{
  public string FooBar { get; set; }
}

and we want it to be serialised to: { "foo_bar": "" }
We could use an attribute:

[JsonProperty(PropertyName = "foo_bar")]
public string FooBar { get; set; }

That will work, however, if we want to generalise this strategy we should create a JsonSerializerSettings with DefaultContactResolver which is using SnakeCaseNamingStrategy and to use it while serialisation/deserialization:

public class JsonCoverter : IJsonConverter
{
 private static JsonSerializerSettings defaultJsonSerializerSettings = 
new JsonSerializerSettings
 {
  ContractResolver = new DefaultContractResolver
  {
   NamingStrategy = new SnakeCaseNamingStrategy()
  }
 };
    
 public T Deserialize<T>(string json) =>
  JsonConvert.DeserializeObject<T>(json, defaultJsonSerializerSettings);
      
 public string Serialize(object obj) =>
  JsonConvert.SerializeObject(obj, defaultJsonSerializerSettings);
   
}

Using the JsonConverter globally will solve the different notation problem.

Saturday, March 4, 2017

How to debug an iOS app build in Xamarin on a real device for free?

"With Apple's release of Xcode 7 came an important change for all iOS and Mac developers–free provisioning."

So all you need is an apple id and to configure your IDE.
There are a lot of guides available out there, so this post is not going to be another one:
Xamarin Developer Guide
- http://stackoverflow.com/a/32249026/1970317

One thing that can be confusing is that first, you need to create a Xcode project with the same "Bundle Identifier" and then download the free provisioning profile. Just pay attention to the uniqueness of your bundle identifier otherwise, it won't work.

Friday, February 10, 2017

Parallels Desktop and Windows 10: Can't open any Mac folder from Windows


For last few months, I had multiple problems with Parallels and Windows 10 but the most annoying problem happened just yesterday. For some reason, I couldn't access shared Mac folders anymore.
Double click simply leads to nothing, however, if I tried to delete a directory I got a "There is a problem accessing \\Mac\Home...".

Luckily I found a solution very quickly. All I had to do is:



Right click on Win10 Icon > Actions > Reinstall Parallels Tools.
Original solution is talking about updating the Parallelels Tools but in my case reinstalling did the trick.

Happy coding!

Tuesday, February 7, 2017

Enterprise and small mistakes made in ASP.NET Web.API


Short Intro

"The only real mistake is the one from which we learn nothing." - Henry Ford

It is important to share our experience to help others avoid stepping into the same bucket.

It was an enterprise distributed project with a small group of developers. Each developer had a different part of the solution to develop and at some point, all of us concentrated on the backend.

The Story

So here is a list of mistakes we made:
  • Security:
    • In some (bad designed) case authentication tokens were sent in a query string as a part of the URL. Please don't try it at home, it's like sharing your username and password with the world. Anyone who will get the URL will be able to access the protected resources.
  • Caching:
    • In memory caching for distributed solution - that might work if you manage to sync the in-memory caches between different nodes, but that was not our case. If you would like to get a bit more information about different caching options please check here and here.
    • Complicated, bad organised and annoying caching system - in most cases we had a lot of dependent cache but in order to clean the dependent cache, we had to write a lot of boilerplate code. However, upon Insert, we could add CacheDependency to simplify the solution for example.
  • Database:
    • We used EntityFramework to work without MSSQL database - but most of our developers were not familiar with "Performance Considerations for EF 4, 5, and 6". This led us to quite slow queries without cached query plans and etc.
    • We ended up with a lot of copy-paste queries - a violation of DRY principle.
    • We had to write a lot of boilerplate code on each request - DTO -> SQL Query -> Entity -> DTO. One of the possible solutions here would be to use Automapper.
  • API:
    • A mix of RESTful and RPC.
    • Almost RESTful - where POSTs used to return data (query).
  • Conflict of interests:
    • Our backend was written in C# and front-end in javascript - we ended up with lowercase property names in our C# DTOs. Well, it's due to different naming conventions but why not use the next solution and let all of the devs be happy?
  • General:
    • SOLID principles were totally ignored.
    • 0 automated tests.
    • DRY principles violated.

Conclusion

At some point, as you can imagine we had to refactor a lot of code, the problem, as usual, was that we had to do it after release because we didn't have any automated tests it was quite risky and hard to achieve. The good news is that we managed to improve the code quality, maintainability and scalability by making baby steps re-factoring and the most important thing is that we managed to deliver a working solution on time. This story ends up well but if we had a good code base from the begging we would be happier and stress less.

Happy coding!

P.S.: Don't judge your colleagues, share your knowledge, thoughts and experience to improve the world.

Friday, February 3, 2017

Adding swagger to ASP.NET Web.Api


Sounds easy right? But it turn to be very confusing. When I first tried to integrate Swashbuckle I met few problems:
  1. Auto generated documentation totally ignored existing and working API endpoints (methods in ApiControllers). So it was totally empty.
  2. After solving the first issue I realised that "/Token" endpoint is still not listed.
  3. Had to find a way to pass a bearer token with each request swagger generated for me.
So let's start solving those problems one by one.
First we have to install Swashbuckle nuget package: Install-Package Swashbuckle
That should generate SwaggerConfig.cs under App_Start folder:

swashbuckle swagger

To solve problem #1 we need to use the right HttpConfiguration:

  1. Remove [assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")] from SwaggerConfig.cs. We will register it manually. 
  2. Change the signature of Register method to public static void Register(HttpConfiguration httpConfig). This will allow us to pass the right HttpConfiguration.
  3. Change GlobalConfiguration.Configuration to httpConfig.EnableSwagger.  This will allow us to use the right HttpConfiguration upon the registration.
swashbuckle swagger

Now we have to manually register our swagger, for that we just have to add one additional line to Startup.cs;

At this point all our API endpoints should be visible if you navigate to http://yourapi:port/swagger

To solve problem number #2 we have to manually define documentation for our /Token endpoint by creating a AuthTokenDocumentFilter.cs (source):

public class AuthTokenDocumentFilter : IDocumentFilter
    {
        public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
        {
            swaggerDoc.paths.Add("/token", new PathItem
            {
                post = new Operation
                {
                    tags = new List { "Auth" },
                    consumes = new List
                {
                    "application/x-www-form-urlencoded"
                },
                    parameters = new List {
                    new Parameter
                    {
                        type = "string",
                        name = "grant_type",
                        required = true,
                        @in = "formData",
                        @default = "password"
                    },
                    new Parameter
                    {
                        type = "string",
                        name = "username",
                        required = false,
                        @in = "formData"
                    },
                    new Parameter
                    {
                        type = "string",
                        name = "password",
                        required = false,
                        @in = "formData"
                    }
                }
                }
            });
        }
The next step will be to add AuthTokenDocumentFilter to our swagger configuration:

At this point "Auth" endpoint will become visible at http://yourapi:port/swagger

To solve problem number #3 we have to make few small changes in SwaggerConfig.cs.
Add the next line inside EnableSwagger section:


c.ApiKey("Token")
 .Description("Bearer token")
 .Name("Authorization")
 .In("header");

Inside EnableSwaggerUi section add the next line:

c.EnableApiKeySupport("Authorization", "header");


Now in order to get a bearer token you can use swagger and if you want to use the retrieved token in all calls simply add it near the "Explore" button:

Good luck!

P.S.: You can get the file from GitHub Gist