json

#CASBAN6: Implementing the API endpoints with Azure Functions

#CASBAN6: Implementing the API endpoints with Azure Functions

After my last post, we have the base implementation ready to be used for our endpoints. As we already know, our endpoints will feature the CRUD pattern to interact with the endpoints. Please note: the code on GitHub is already a few steps ahead and may look a bit different from what I am posting here (mostly due to the OpenApi attributes, but you will be able to follow along).

I will use the AuthorFunction to demonstrate the implementation. All other function implementations besides the BlogFunction follow the same pattern.

Let’s dive in

First, we create a new class that derives from our base class. The constructor initializes the EF context as well as the ILogger for the author function. On top, we are defining the Route template that our functions are going to use as constant, so we can refer it in the function’s attributes. You should now have something similar to this:

public class AuthorFunction : BlogFunctionBase
{
    private const string Route = "blog/{blogId}/author";

    public AuthorFunction(BlogContext blogContext, ILoggerFactory loggerFactory) : base(blogContext) =>
        Logger = loggerFactory.CreateLogger<AuthorFunction>();
}

Override the Create method

The Create function is obviously responsible for creating a new entry in our database. First, we check if the blogId query parameter was specified and if it is parsable as a Guid. This step is the same for all endpoints. If these checks succeed, we are moving on to the next step, in this case deserializing the submitted Author DTO.

We are using then the CreateFrom mapping extension method to transform the DTO into the EntityModel.Author object (read my post on DTOs and mappings here). The latter one can then be added to the context’s authors list and saved. If all goes well, we create a 201 Created response indicating the direct API url to read the newly created author. In all other cases, we have some error handling in place.

[Function($"{nameof(AuthorFunction)}_{nameof(Create)}")]
public override async Task<HttpResponseData> Create([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = Route)] HttpRequestData req, string blogId)
{
    try
    {
        if (string.IsNullOrWhiteSpace(blogId) || Guid.Parse(blogId) == default)
            return await req.CreateResponseDataAsync(HttpStatusCode.BadRequest, "Required parameter 'blogId' (GUID) is not specified or cannot be parsed.");


        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

        Author? author = JsonConvert.DeserializeObject<Author>(requestBody);

        if (author != null)
        {

            EntityModel.Author? newAuthorEntity = author.CreateFrom(Guid.Parse(blogId));

            EntityEntry<EntityModel.Author> createdAuthor =
                BlogContext.Authors.Add(newAuthorEntity);

            await BlogContext.SaveChangesAsync();

            return await req.CreateNewEntityCreatedResponseDataAsync(createdAuthor.Entity.AuthorId);
        }
        else
        {
            return await req.CreateResponseDataAsync(HttpStatusCode.BadRequest, "Submitted data is invalid, author cannot be created.");
        }
    }
    catch (Exception ex)
    {
        Logger.LogError(ex, "Error creating author object on blog with Id {BlogId}", blogId);
        return await req.CreateResponseDataAsync(HttpStatusCode.InternalServerError, "An internal server error occured. Error details logged.");
    }
}

Override the GetList method

We are using the GetList method to retrieve a list of entities. This method employs also the count and skip parameters, which is a simple way of implementing paging. We are using the ToDto method on the EnityModel.Author list to return the entities to the caller.

If something is going wrong during the function call, we have some error handling in place.

[Function($"{nameof(AuthorFunction)}_{nameof(GetList)}")]
public override async Task<HttpResponseData> GetList([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = Route)] HttpRequestData req, string blogId)
{
    try
    {
        Logger.LogInformation("Trying to get authors...");

        if (string.IsNullOrWhiteSpace(blogId) || Guid.Parse(blogId) == default)
            return await req.CreateResponseDataAsync(HttpStatusCode.BadRequest, "Required parameter 'blogId' (GUID) is not specified or cannot be parsed.");

        (int count, int skip) = req.GetPagingProperties();

        List<EntityModel.Author> entityResultSet = await BlogContext.Authors.
                                                                     Include(author => author.UserImage).
                                                                     ThenInclude(media => media.MediumType).
                                                                     Where(author => author.BlogId == Guid.Parse(blogId)).
                                                                     Skip(skip).
                                                                     Take(count).
                                                                     ToListAsync();

        List<Author> resultSet = entityResultSet.Select(entity => entity.ToDto()).ToList();

        return await req.CreateOkResponseDataWithJsonAsync(resultSet, JsonSerializerSettings);
    }
    catch (Exception ex)
    {
        Logger.LogError(ex, "Error getting author list for blog with Id \'{Id}\'", blogId);
        return await req.CreateResponseDataAsync(HttpStatusCode.InternalServerError, "An internal server error occured. Error details logged.");
    }
}

Override the GetSingle method

The GetSingle endpoint needs also the id of the desired entity to be executed. This call is for getting just a single author from the database. Also here we have our error handling in place.

[Function($"{nameof(AuthorFunction)}_{nameof(GetSingle)}")]
public override async Task<HttpResponseData> GetSingle([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = Route + "/{id}")] HttpRequestData req, string blogId, string id)
{
    try
    {
        if (string.IsNullOrWhiteSpace(blogId) || Guid.Parse(blogId) == default)
            return await req.CreateResponseDataAsync(HttpStatusCode.BadRequest, "Required parameter 'blogId' (GUID) is not specified or cannot be parsed.");
        
        if (!string.IsNullOrWhiteSpace(id))
        {
            Logger.LogInformation("Trying to get author with Id: {Id}...", id);

            EntityModel.Author? existingAuthor =
                await BlogContext.Authors.
                                  Include(author => author.UserImage).
                                  ThenInclude(media => media.MediumType).
                                  SingleOrDefaultAsync(author => author.BlogId == Guid.Parse(blogId) &&
                                                                 author.AuthorId == Guid.Parse(id));

            if (existingAuthor == null)
            {
                Logger.LogWarning("Author with Id {Id} not found", id);
                return req.CreateResponse(HttpStatusCode.NotFound);
            }

            return await req.CreateOkResponseDataWithJsonAsync(existingAuthor.ToDto(), JsonSerializerSettings);
        }
        else
        {
            return await req.CreateResponseDataAsync(HttpStatusCode.BadRequest, "Submitted data is invalid, must specify BlogId");
        }
    }
    catch (Exception ex)
    {
        Logger.LogError(ex, "Error getting author with Id '{AuthorId}' for blog with Id \'{BlogId}\'", id, blogId);
        return await req.CreateResponseDataAsync(HttpStatusCode.InternalServerError, "An internal server error occured. Error details logged.");
    }
}

Override the Update method

The structure of the Update function should be no surprise. First check the blog’s id, then read the submitted Author DTO. If the author already exists, update the information of the Author in the database. Otherwise, tell the caller there is no such author.

[Function($"{nameof(AuthorFunction)}_{nameof(Update)}")]
public override async Task<HttpResponseData> Update([HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = Route + "/{id}")] HttpRequestData req, string blogId, string id)
{
    try
    {
        if (string.IsNullOrWhiteSpace(blogId) || Guid.Parse(blogId) == default)
            return await req.CreateResponseDataAsync(HttpStatusCode.BadRequest, "Required parameter 'blogId' (GUID) is not specified or cannot be parsed.");

        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

        Author? authorToUpdate = JsonConvert.DeserializeObject<Author>(requestBody);

        if (authorToUpdate != null)
        {
            EntityModel.Author? existingAuthor =
                await BlogContext.Authors.
                                  Include(author => author.UserImage).
                                  ThenInclude(media => media.MediumType).
                                  SingleOrDefaultAsync(author => author.BlogId == Guid.Parse(blogId) &&
                                                                 author.AuthorId == Guid.Parse(id));

            if (existingAuthor == null)
            {
                Logger.LogWarning("Author with Id {Id} not found", id);
                return req.CreateResponse(HttpStatusCode.NotFound);
            }

            existingAuthor.UpdateWith(authorToUpdate);

            await BlogContext.SaveChangesAsync();

            return req.CreateResponse(HttpStatusCode.Accepted);
        }
        else
        {
            return await req.CreateResponseDataAsync(HttpStatusCode.BadRequest, "Submitted data is invalid, author cannot be modified.");
        }
    }
    catch (Exception ex)
    {
        Logger.LogError(ex, "Error updating author with Id '{AuthorId}' for blog with Id \'{BlogId}\'", id, blogId);
        return await req.CreateResponseDataAsync(HttpStatusCode.InternalServerError, "An internal server error occured. Error details logged.");
    }
}

Override the Delete method

Last but not least, we sometimes need to delete entities for whatever reason. This is where the Delete function comes into play. This function requires both the blog’s id and the entity’s id to be executed. As with all other functions, there is some error handling in place.

[Function($"{nameof(AuthorFunction)}_{nameof(Delete)}")]
public override async Task<HttpResponseData> Delete([HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = Route + "/{id}")] HttpRequestData req, string blogId, string id)
{
    try
    {
        if (string.IsNullOrWhiteSpace(blogId) || Guid.Parse(blogId) == default)
            return await req.CreateResponseDataAsync(HttpStatusCode.BadRequest, "Required parameter 'blogId' (GUID) is not specified or cannot be parsed.");

        EntityModel.Author? existingAuthor = await BlogContext.Authors.
                                                               Include(author => author.UserImage).
                                                               SingleOrDefaultAsync(author => author.BlogId == Guid.Parse(blogId) &&
                                                                                              author.AuthorId == Guid.Parse(id));

        if (existingAuthor == null)
        {
            Logger.LogWarning("Author with Id {Id} not found", id);
            return req.CreateResponse(HttpStatusCode.NotFound);
        }

        BlogContext.Authors.Remove(existingAuthor);

        await BlogContext.SaveChangesAsync();

        return req.CreateResponse(HttpStatusCode.OK);
    }
    catch (Exception ex)
    {
        Logger.LogError(ex, "Error deleting author with Id '{AuthorId}' from blog with Id \'{BlogId}\'", id, blogId);
        return await req.CreateResponseDataAsync(HttpStatusCode.InternalServerError, "An internal server error occured. Error details logged.");
    }
}

Helper methods

You might have noticed that there are some extensions methods in the code samples above you haven’t seen so far. I got you, here they are.

Paging properties

To get the paging properties (I use simple paging here), we have the query parameters count and skip. To extract them from the request, we do some parsing on the parameters that the HttpRequestData provides us.

private static Dictionary<string, string> GetQueryParameterDictionary(this HttpRequestData req)
{
    Dictionary<string, string> result = new Dictionary<string, string>();

    string queryParams = req.Url.GetComponents(UriComponents.Query, UriFormat.UriEscaped);

    if (!string.IsNullOrWhiteSpace(queryParams))
    {
        string[] paramSplits = queryParams.Split('&');

        if (paramSplits.Any())
        {
            foreach (string split in paramSplits)
            {
                string[] valueSplits = split.Split('=');

                if (valueSplits.Any() && valueSplits.Length == 2)
                    result.Add(valueSplits[0], valueSplits[1]);
            }
        }
    }
    return result;
}

public static (int count, int skip) GetPagingProperties(this HttpRequestData req)
{
    Dictionary<string, string> queryParams = req.GetQueryParameterDictionary();

    int count = 10;
    int skip = 0;

    if (queryParams.Any(p => p.Key == nameof(count)))
        _ = int.TryParse(queryParams[nameof(count)], out count);

    if (queryParams.Any(p => p.Key == nameof(skip)))
        _ = int.TryParse(queryParams[nameof(skip)], out skip);

    return (count, skip);
}

HttpResponseData helpers

Our function will run in an isolated process. Besides having a bunch of advantages like easier dependency injection, it brings also some syntax changes. As you can see from the docs, we are now responding with a HttpResponseData object. For easier creation of these objects, I wrote these extensions:

public static async Task<HttpResponseData> CreateResponseDataAsync(this HttpRequestData req, HttpStatusCode statusCode, string? message)
{
    HttpResponseData response = req.CreateResponse(statusCode);

    if (string.IsNullOrWhiteSpace(message))
        message = statusCode.ToString();

    await response.WriteStringAsync(message);

    return response;
}

public static async Task<HttpResponseData> CreateNewEntityCreatedResponseDataAsync(this HttpRequestData req, Guid createdResourceId)
{
    HttpResponseData response = req.CreateResponse(HttpStatusCode.Created);
    response.Headers.Add("Location", $"{req.Url}/{createdResourceId}");

    await response.WriteStringAsync("OK");

    return response;
}

public static async Task<HttpResponseData> CreateOkResponseDataWithJsonAsync(this HttpRequestData req, object responseData, JsonSerializerSettings? settings)
{
    string json = JsonConvert.SerializeObject(responseData, settings);
    
    HttpResponseData response = req.CreateResponse(HttpStatusCode.OK);
    response.Headers.Add("Content-Type", "application/json; charset=utf-8");

    await response.WriteStringAsync(json);

    return response;
}

The first one creates a response with the specified HttpStatusCode and an optional message. The second one is for the 201 Created responses, while the last one is for the 200 OK responses.

The BlogFunction

The BlogFunction implmentation is the only one not deriving from the base class. As the blog is the root entity, there are some differences from the pattern above.

The Create method in this function works without the blog’s id, but otherwise is the same as for all other Create methods.

The GetBlogList method features count properties for its child entities (authors, posts, tags, media) and does also not need the blog’s id. Details of child entities should be loaded via their function implementations.

The GetBlog method tries to load a blog completely with all child entities. This may result in a very large data set and should be used with caution and for exports only.

The Update and Delete methods are once again following the pattern of the other functions, except they just need the blog’s id.

You can have a look at the BlogFunction right here on GtiHub.

Anonymous authorization

If you are wondering why all the functions have the AuthorizationLevel set to Anonymous, I got you. Once the function is deployed to Azure, we will use the Azure Active Directory to force a login to a Microsoft account (others may follow) to call our functions. We have a strong protection this way without big efforts.

Conclusion

In this post, I showed you how to use the base class we created in the last post of the series, and also showed you how the BlogFunction differs from that. In the next post, we will have a look at how to add Swagger to our Functions that will make API testing a lot easier as we advance with our project. With each post, we are getting closer to deploy the API functions to Azure, so stay tuned for the next post(s)!

Until the next post, happy coding, everyone!

Posted by msicc in Azure, Dev Stories, 0 comments
How to host a code file on Github as Gist to use in your application

How to host a code file on Github as Gist to use in your application

What the h*** is a Gist?

In case you never heard of Gist, it is an easy to use way to share code files hosted by Github. Everyone with a user account can use this feature, and now that also the premium features are free (thanks to the acquisition by Microsoft), you can even share them secretly.

Where do I find my Gists?

This one is for the beginners. If you know this already, move on. Once you have logged into your Github account, click on your user name. This will open a menu where you can see an option called ‘Your gists’. Once you clicked that one, you will see a page similar to mine (maybe with no gists in it):

gist_overview_gists

How to create a new Gist?

Well, that’s pretty easy. You just click on the ‘+’-button besides your user avatar in the top right corner:

gist_menu_add_new

This will bring up a new gist window. Enter your description, file name and fill in the content of your file or even add more files and hit the ‘Create public gist’ button to create your new gist. If you intend to host multiple files in your gist, please note that you will need the following steps on every single file you add (as each one has its own url).

gist_add_new

How to use this Gist in my app?

Luckily, both files in Github repos as well as in gists can be viewed in the so called ‘Raw’ view. You will find a corresponding button on every code file in the top right corner. Click on it, and you will see a plain-text representation (here is a sample from the one that led to this block post. It is styled by a browser extension that makes json more readable (every developer should already have one of this type installed, btw)):

gist_raw_view

Now we are close to be able to fetch this file into our applications. If you are sure that this file will never change, just use this file. If you know that this file is subject for future changes, you will need to perform a little trick.

Getting always the latest version of our Gist

If you analyze the url, you will notice that there is a unique id between the ‘raw’ part and the file name:

gist_remove_this_id

This id represents the current revision of your Gist. To make sure we always get the latest version of our gist, we need to remove this id. The url must end with ‘raw/yourfile.extensions‘, as you can see here:

gist_always_latest_revision_url

This way, you can update the file and implement an update mechanism into your app that fetches always the latest revision of that file. To fetch the file content into your app, you just need to perform a GET request against that url, without the overload of using Github’s API.

Conclusion

Instead of hosting configuration or data files on a private web server, one can utilize existing infrastructure like the one of Github. Like always, I hope this post will be helpful for some of you.

Until the next post, happy coding, everyone!
Posted by msicc in Dev Stories, Xamarin, 1 comment
Xamarin.Forms, Akavache and I: storing, retrieving and deleting data

Xamarin.Forms, Akavache and I: storing, retrieving and deleting data

Caching always has the same job: provide data that is frequently used in very little time. As I mentioned in my first post of this series, Akavache is my first choice because it is fast. It also provides a very easy way to interact with it (once one gets used to Reactive Extensions). The code I am showing here is living in the Forms project, but can also be called from the platform projects thanks to the interface we defined already before.

Enabling async support

First things first: we should write our code asynchronously, that’s why we need to enable async support by adding using System.Reactive.Linq;to the using statements in our class. This one is not so obvious, and I read a lot of questions on the web where this was the simple solution. So now you know, let’s go ahead.

Simple case

The most simple case of storing data is just throwing data with a key into the underlying database:

//getting a reference to the cache instance
var cache = SimpleIoc.Default.GetInstance<IBlobCacheInstanceHelper>().LocalMachineCache;
var dataToSave = "this is a simple string to save into the database";
await cache.InsertObject<string>("YourKeyHere", dataToSave);

Of course, we need a reference to the IBlobCacheinstance we have already in place. I am saving a simple string here for demo purposes, but you can also save more complex types like a list of blog posts into the cache. Akavache uses Json.NET , which will serialize the data into a valid json string that you can be saved. Similarly, it is very easy to get the data deserialized from the database:

var dataFromCache = cache.GetObject<string>("YourKeyHere");

That’s it. For things like storing Boolean values, simple strings (unencrypted), dates etc., this might already be everything you need.

Caching data from the web

Of course it wouldn’t be necessary to implement an advanced library if we would have only this scenario. More often, we are fetching data from the web and need to save it in our apps. There are several reasons to do this, with saving (mobile) data volume and performance being the two major reasons.

Akavache provides a bunch of very useful Extensions. The most prominent one I am using is the GetOrFetchObject<T>method. A typical implementation looks like this:

var postsCache = await cache.GetOrFetchObject<List<BlogPost>>(feedName,
    async () =>
    {
        var newPosts = await _postsHandler.GetPostsAsync(BaseUrl, 20, 20, 1, feedName.ToCategoryId()).ConfigureAwait(false);

        await cache.InsertObject<List<BlogPost>>(feedName, newPostsDto);

        return newPosts;
    });

The GetOrFetchObject<T>method’s minimum parameters are the key of the cache entry and an asynchronous function that shall be executed when there is no data in the cache. In the sample above, it loads the latest 20 posts from a WordPress blog (utilizing my WordPressReader lib) and saves it into the cache instance before returning the downloaded data. The method has an optional parameter of DateTimeOffset, which may be interesting if you need to expire the saved data after some time.

Saving images/documents from the web

If you need to download files, be it images or other documents, from the web, Akavache provides another helper extension:

byte[] bytes = await cache.DownloadUrl("YourFileKeyHere", url);

Personally, I am loading all files with this method, even though there are some special image loading methods available as well (see the readme at Akavache’s repo). The main reason I am doing so is that until now, I always have a platform specific implementation for such cases – mainly due to performance reasons. I one of the following blog posts you will see such an implementation for image caching using a custom renderer on each platform.

Deleting data from the cache

When working with caches, one cannot avoid the situation that data needs to be removed manually from the cache.

//delete a single entry by key:
cache.Invalidate("KeyToDelete");

//delete all entries with the same type:
cache.InvalidateAllObjects<BlogPost>();

//delete all entries
cache.InvalidateAll();

If you want to continue with some other action after deletion completes, you can use the Subscribe method to invoke this action:

cache.InvalidateAll().Subscribe(x => YourMethodToInvoke());

Conclusion

Even though Akavache provides more methods to store and retrieve data, the ones I mentioned above are those that I use frequently and without problems in my Xamarin.Forms applications, while still being able to invoke them in platform specific code as well. If you want to have a look at the other methods that are available, click the link above to the GitHub repo of Akavache. As always, I hope this blog post is helpful for some of you.

Until the next post, happy coding, everyone!

Posted by msicc in Android, Dev Stories, iOS, Windows, Xamarin, 1 comment
Xamarin.Forms, Akavache and I: Initial setup (new series)

Xamarin.Forms, Akavache and I: Initial setup (new series)

Caching is never a trivial task. Sometimes, we can use built-in storages, but more often, these take quite some time when we are storing a large amount of data (eg. large datasets or large json strings). I tried quite a few approaches, including:

  • built-in storage
  • self handled files
  • plugins that use a one or all of the above
  • Akavache (which uses SQLite under the hood)

Why Akavache wins

Well, the major reason is quite easy. It is fast. Really fast. At least compared to the other options. You may not notice the difference until you are using a background task that relies on the cached data or until you try to truly optimize startup performance of your Xamarin Android app. Those two where the reason for me to switch, because once implemented, it does handle both jobs perfectly. Because it is so fast, there is quite an amount of apps that uses it. Bonus: there are a lot of tips on StackOverflow as well as on GitHub, as it is already used by a lot of developers.

Getting your projects ready

Well, as often, it all starts with the installation of NuGet packages. As I am trying to follow good practices wherever I can, I am using .netStandard whenever possible. The latest stable version of Akavache does work partially in .netStandard projects, but I recommend to use the latest alpha (by the time of this post) in your .netStandard project (even if VisualStudio keeps telling you that a pre release dependency is not a good idea). If you are using the package reference in your project files, there might be some additional work to bring everything to build and run smoothly, especially in a Xamarin.Android project.

You mileage may vary, but in my experience, you should install the following dependencies and Akavache separately:

After installing this packages in your Xamarin.Forms and platform projects, we are ready for the next step.

Initializing Akavache

Basically, you should be able to use Akavache in a very simple way, by just defining the application name like this during application initialization:

BlobCache.ApplicationName = "MyAkavachePoweredApp";

You can do this assignment in your platform project as well as in your Xamarin.Forms project, both ways will work. Just remember to do this, as also to get my code working, this is a needed step.

There are static properties  like BlobCache.LocalMachineone can use to cache data. However, once your app will use an advanced library like Akavache, it is very likely that he complexity of your app will force you into a more complex scenario. In my case, the usage of a scheduled job on Android was the reason why I am doing the initialization on my own. The scheduled job starts a process for the application, and the job updates data in the cache that the application uses. There were several cases where the standard initialization did not work, so I decided to make the special case to a standard case. The following code will also work in simple scenarios, but keeps doors open for more complex ones as well. The second reason why I did my own implementation is the MVVM structure of my apps.

IBlobCacheInstanceHelper rules them all

Like often when we want to use platform implementations, all starts with an interface that dictates the functionality. Let’s start with this simple one:

public interface IBlobCacheInstanceHelper
{
    void Init();
    IBlobCache LocalMachineCache { get; set; }
}

We are defining our own IBlobCacheinstance, which we will initialize with the Init() method on each platform. Let’s have a look on the platform implementations:

[assembly: Xamarin.Forms.Dependency(typeof(PlatformBlobCacheInstanceHelper))]
namespace [YOURNAMESPACEHERE]
{
    public class PlatformBlobCacheInstanceHelper : IBlobCacheInstanceHelper
    {
        private IFilesystemProvider _filesystemProvider;

        public PlatformBlobCacheInstanceHelper() { }

        public void Init()
        {
            _filesystemProvider = Locator.Current.GetService<IFilesystemProvider>();
            GetLocalMachineCache();
        }

        public IBlobCache LocalMachineCache { get; set; }

        private void GetLocalMachineCache()
        {

            var localCache = new Lazy<IBlobCache>(() => 
                                                  {
                                                      _filesystemProvider.CreateRecursive(_filesystemProvider.GetDefaultLocalMachineCacheDirectory()).SubscribeOn(BlobCache.TaskpoolScheduler).Wait();
                                                      return new SQLitePersistentBlobCache(Path.Combine(_filesystemProvider.GetDefaultLocalMachineCacheDirectory(), "blobs.db"), BlobCache.TaskpoolScheduler);
                                                  });

            this.LocalMachineCache = localCache.Value;
        }

        //TODO: implement other cache types if necessary at some point
    }
}

Let me explain what this code does.

As SQLite, which is powering Akavache, is file based, we need to provide a file path. The Init() method assigns Akavache’s internal IFileSystemProviderinterface to the internal member. After getting an instance via Splat’s Locator, we can now use it to get the file path and create the .db-file for our local cache. The GetLocalMachineCache()method is basically a copy of Akavache’s internal registration. It lazily creates an instance of BlobCache through the IBlobCacheinterface. The create instance is then passed to the LocalMachineCacheproperty, which we will use later on. Finally, we will be using the DependencyServiceof Xamarin.Forms to get an instance of our platform implementation, which is why we need to define the Dependency attribute as well.

Note: you can name the file whatever you want. If you are already using Akavache and want to change the instance handling, you should keep the original names used by Akavache. This way, your users will not lose any data.

This implementation can be used your Android, iOS and UWP projects within your Xamarin.Forms app. If you are wondering why I do this separately for every platform, you are right. Until now, there is no need to do it that way. The code above would also work solely in your Xamarin.Forms project. Once you are coming to the point where you need encrypted data in your cache, the platform implementations will change on every platform. This will be topic of a future blog post, however.

If you have been reading my series about MVVMLight, you may guess the next step already. This is how I initialize the platform implementation within my ViewModelLocator:

//register:
var cacheInstanceHelper = DependencyService.Get<IBlobCacheInstanceHelper>();
if (!SimpleIoc.Default.IsRegistered<IBlobCacheInstanceHelper>())
     SimpleIoc.Default.Register<IBlobCacheInstanceHelper>(()=> cacheInstanceHelper);

//initialize:
//cacheInstanceHelper.Init();
//or
SimpleIoc.Default.GetInstance<IBlobCacheInstanceHelper>().Init();

So that’s it, we are now ready to use our local cache powered by Akavache within our Xamarin.Forms project. In the next post, we will have a look on how to use akavache for storing and retrieving data.

Until then, happy coding, everyone!

Posted by msicc in Android, Dev Stories, iOS, Windows, Xamarin, 1 comment

How to fetch articles from your uservoice knowledgebase into a Windows Phone app

As some of you might know, I recently switched to uservoice.com for feedback, support and also FAQ hosting (read more here). Of course I want to integrate all those features into my app(s) to make the user experience as native as possible.

First, you need to generate a new app in uservoice.com. Log into your account, click on ‘Admin Console’, ‘Settings’ and finally ‘Integrations’. Then add your API client, you will have something like this:

uservoice_api_client

Today, we are starting with getting our knowledge base articles into our app.

This is the easiest part besides assigning the support mail address to a button.

Here is how we are doing it:

First, we need to declare some constants:

//consumer key and secret are needed to authorize our requests (oAuth)
 //KB articles only need the ConsumerKey
 const string ConsumerKey = "<youKey>";
 const string ConsumerSecret = "<yourSecret>";
 //all KB articles:
 const string KnowledgebaseString = "http://<yoursubdomain>.uservoice.com/api/v1/articles.json?client={0}";
 //KB topic articles:
 //using sort=oldest ensures that you will get the right order of your articles
 const string KnowledgebaseTopicString = "http://<yousubdomain>.uservoice.com/api/v1/topics/{0}/articles.json?client={1}&sort=oldest";

static string articleJsonString;

As you can see, we have two options to fetch our knowledgebase articles – all articles (if you have only one app, you’re fine with that) or topic based.

To get the needed topic id, just open the topic in your browser. The topic id is part of the url:

uservoice_topic_id

For getting authorized to receive the JSON string of our knowledge base, we need to pass the consumer key as parameter “client” to the base url of our request. To get our list sorted, I am using the sort parameter as well.

To receive the JSON string, we are creating an async Task<string> that fetches our article. To make the result reloadable, add the IfModifiedSince Header (otherwise Windows Phone caches the result during the app’s current lifecycle).

//receiving the JSON string for our KB does not need any advanced requests: 
//a basic HttpClient handles everything for us, as we don't need any authentication here
public async Task<string> GetKBJsonString()
{
      string getKBJSonStringFromUserVoice = string.Empty;

     HttpClient getKBJsonClient = new HttpClient();
     getKBJsonClient.DefaultRequestHeaders.IfModifiedSince = DateTime.Now;

     getKBJSonStringFromUserVoice = await getKBJsonClient.GetStringAsync(new Uri(string.Format(KnowledgebaseTopicString, "47463", ConsumerKey), UriKind.RelativeOrAbsolute));

      return getKBJSonStringFromUserVoice;
 }

Of course we want to have a list shown to our users – to display our JSON string in a ListBox, we need to deserialize it. To be able to deserialize it, we need a data class. You can use json2sharp.com to generate the base class or use this one (download Link). It fits for both all articles or topic based articles.

First, create a ListBox with the corresponding DataTemplate (I am only using question and answer text for this demo).

            <ListBox x:Name="FAQListBox">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"></RowDefinition>
                                <RowDefinition Height="Auto"></RowDefinition>
                            </Grid.RowDefinitions>
                            <TextBlock Grid.Row="0" x:Name="questionTB" Style="{StaticResource PhoneTextTitle2Style}" Text="{Binding question}" TextWrapping="Wrap"></TextBlock>
                            <TextBlock Grid.Row="1" x:Name="answerTB" Style="{StaticResource PhoneTextSubtleStyle}" Text="{Binding text}" TextWrapping="Wrap"></TextBlock>
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

I am using JSON.net for everything around JSON strings. Here is how to deserialize the JSON string and set the ItemsSource of our Listbox:

            articleJsonString = await GetKBJsonString();

            var articlesList = JsonConvert.DeserializeObject<KBArticleDataClass.KBArticleData>(articleJsonString);

            FAQListBox.ItemsSource = articlesList.articles;

You are now already able to run the project. Here is the result of my test app, displaying the FAQ of my NFC Toolkit app:

uservoice_listbox_testapp_screenshot

As you can see, it takes only about ten minutes to get the knowledge base into your app. Using a remote source has a lot of advantages, the most important one is you don’t need to update your app when you add new answered questions.

I am now starting to work on integrating the feedback forum. It requires an oAuth authentication, and will be a bit more complicated than this one. Of course I will share it with you all here on my blog – stay tuned.

Until then – happy coding!

Posted by msicc in Archive, 3 comments

Dev Story Series (Part 5 of many): Styling a WebView or WebBrowser element

This post is about styling our WebView or WebBrowser in our app. Until now, we only got the HTML string that we are displaying in our WebView or WebBrowser. It looks like this:

image.png

The content we receive from our WordPress post content includes already all kind of HTML tags like paragraphs, lists, links, images. That is the advantage for this solution: no parsing is needed, the string can be displayed as is. Both the WebView and the WebBrowser framework element (no, they are not controls) are able to read and render CSS code. And this is how we can match the whole element for our app.

HTML Pages can be styled by using a so called cascading style sheet (CSS), which is similar to XAML code. With a little bit of searching on the web you will be able to style “translate” your XAML properties into CSS.

Here is a sample CSS String:

<STYLE type="text/css">
body{background:#034786; width:450px; }
p{font-family:'Segoe UI';color: white;font-size:medium;}
h1{font-family:'Segoe UI';color: white;}
h2{font-family:'Segoe UI';color: white;}
h3{font-family:'Segoe UI';color: white;}
h4{font-family:'Segoe UI';color: white;}
pre{background-color: #C0C0C0; width:100%;}
blockquote{font-family:'Segoe UI';font-style:italic;}
a:link{font-family: 'Segoe UI';color: #C0C0C0; font-size: medium; text-decoration:underline}
li{font-family: 'Segoe UI';color: white;font-size: medium;list-style-type: square;}
img {text-align:center; width:100%: height:100%;}
</STYLE>";

Every CSS string has to be surrounded with “<STYLE type=”text/css”> </STYLE> “. Between those two Style tags, you can set different properties for each kind of HMTL tag:

  • body = the whole page is embedded in the body. this is where we set the background of our content as well as the width and the height
  • p = paragraphs. paragraphs can contain text as well as images or other multimedia content. Mainly used for text like in our blog post, we style how the user is able to read our blog post.
  • h1 – h4 = different kinds of headers. you can define four styles of headers
  • pre = is for lines of code
  • blockquote = if we quote people or other sites, we use quotes to clarify this aren’t our words. should be styled a bit differently than the rest of our blog (e.g. Italic)
  • a:link = how hyperlinks will be styled
  • li = this is how our list will be styled in this view
  • img = how we want to see our pictures in our post

Hint for using CSS in code behind:

If you just C&P the CSS string from above, it will result in some errors from Visual Studio. Visual Studio does not like the new lines in strings, so you have to add it as one line. Also is it not possible to use ‘”‘ within a string declaration. It has to be “escaped”, which we are doing with a simple before it: ‘”‘. I mentioned it because I learned it the very hard way by trying to solve it for 2 hours.

Only thing we now need to do is pass the CSS String together with our HTML string from our JSON to our WebView or WebBrowser element:

WebBrowser.NavigateToString(CSSString + ContentString);

After navigating to this both strings, our content is now displayed like native:

  styledNativeWebView

One last tip:

I recommend to set the Visibility of your WebBrowser or WebView to “Collapsed” until the whole rendering has done. Once the “navigation” has finished, set it via code to visible. This way the user does not recognize that we are rendering the post content for him. Just display a loading animation until that is done. Both elements have a “LoadCompleted” event. Once the rendering (= the navigation to our string) is done, the content of our blog post is shown as it would be natively in our app.

As always, I hope this is helpful for some of you and feel free to leave a comment below.

Posted by msicc in Archive, 0 comments

Dev Story Series (Part 3 of many): Why I use a WebBrowser/WebView to display WordPress post content

When it comes to display the post content on a blog reader app, it starts to become a bit challenging. The post content is formatted to look great on your website. But when we pull our posts into an app, there is only the naked, HTML formatted string.

As developer, you have to think about several things now:

  • What part of the content do I want to be displayed?
  • How do I get the images there?
  • What if there is a video in the post?
  • Where do I put the Links in?
  • How can I handle enumerations?
  • and so on…

There is the HTMLAgilityPack out there, but I never got a satisfying result out of it. The next method would be to write a custom parser. This is what I have done before, in the old version of the app for my WordPress blog. It did work, but I had to invest a real big amount of time in it before I got a result that I was able to live with. I was also not too experienced with RegEx (and I am still not) that I could set up a perfect parser.

When I was creating the Windows 8 version of my app, I wanted to achieve a good reading experience. On the other side I  wanted the code to be as reliable as possible, because there are often changes on WordPress that can have impact on my app.

As I mentioned above, the post content is already formatted. It is formatted in HTML.  I decided to render the content string instead of parsing it.

It is pretty easy to do that. Just pass the content string to your desired details page, and use a WebBrowser on Windows Phone or a WebView on Windows 8. Without any parsing, just by “navigating” to the passed string, we will get a result like this:

image

So we have already a readable result, and if my app has only white background, I could leave it like it is and go on.  Without any additional line of code.

Using the WebBrowser/WebView brings also additional advantages:

  • Pinch-to-Zoom support
  • Orientation support
  • automatic image downloading without any additional control
  • WebView on Windows 8 embeds videos automatically

I don’t want to hide that there are a few points that we need to handle, which will be subject of additional posts:

  • styling of content to match our app colors
  • Navigation to links (including a solution for video links on Windows Phone)
  • Scroll direction in Windows 8 WebView

I know it might be not the best practice for displaying web content, but I am really satisfied what I achieved by using the WebBrowser and WebView element in my apps.

I hope the upcoming blog posts will be helpful for some of you to create also a good user experience by using these elements. Of course these posts will contain some code. Before starting the posts about it I just wanted to share why I used these elements.

 

Posted by msicc in Archive, 0 comments

Dev Story Series (Part 2 of many): Getting recent posts from WordPress into your Windows Phone and Windows 8 app

Now that we have a full WordPress JSON class, we are able to download our recent posts from WordPress into our apps for Windows Phone and Windows 8. I am still not using MVVM to keep it simple (and because I have to dive into it more deeply).

The first thing we need to do is to download the JSON string for the recent posts. The Uri scheme is pretty simple: {yourblogadresshere}?json=get_recent_posts

I declared a public string in my MainPage for that, so it is very easy to use it in our app.

The second thing we are going to do is to download the JSON string into the app.

For Windows Phone I used a WebClient, as I want to keep it compatible with the Windows Phone 7 OS. I will update the App with an dedicated WP8 version later, for the moment it is working on both OS versions. Add this code to you Page_Loaded event:

                WebClient GetPostsClient = new WebClient();
                GetPostsClient.Headers[HttpRequestHeader.IfModifiedSince] = DateTime.Now.ToString();
                GetPostsClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(GetPostsClient_DownloadStringCompleted);
                GetPostsClient.DownloadStringAsync(new Uri(RecentPostJsonUri));

We will also have to add the Handler for GetPostsClient_DownloadStringCompleted:

 void GetPostsClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            App.jsonString_result = e.Result;
        }

In Windows 8 there is no WebClient, so I used an HttpClient:

                        HttpClient getJsonStringClient = new HttpClient();
                        getJsonStringClient.DefaultRequestHeaders.IfModifiedSince = DateTime.UtcNow;
                        App.jsonString_result = await getJsonStringClient.GetStringAsync(RecentPostJsonUri);

Both the Windows Phone and the Windows 8 apps are downloading the string asynchronously, the UI is reliable all the time. You may have noticed the additional Header that I request. This way, we are able to integrate a refresh function into our app. If we leave this out, our app uses the cached string, and users will have to exit the app to refresh the list of our posts.

You will have to declare a public static string variable for the downloaded string in App.xaml.cs, that keeps the downloaded string accessible through the whole app.

Until now we have only downloaded our JSON String, which looks like this:

image

Side note: The WordPress JSON API has a dev mode. Just add “&dev=1” to your above created Uri, and you will be able to see the whole JSON string in a readable form in your browser.

Back to our topic. Off course this is not a good format for users. They want to see only the content, without all the formatting and structuring code around.

What we need to do, is to deserialize our JSON String. This is possible with Windows Phone and Windows 8 own API, but I highly recommend to use the JSON.net library. You can download and learn more about it here. To install the library, just go to Tools>Library Package Manager>Manage NuGet Packages for Solution, search for JSON.net, and install it.

After installing the package, we are able to use only one line of code to deserialize our JSON String to our data members:

var postList = JsonConvert.DeserializeObject<Posts>(App.jsonString_result);

Now we need the deserialized data to be displayed to the user. The desired control for Windows Phone is a ListBox, for Windows 8 you it is called  ListView. We need to create an ItemTemplate in XAML and bind the data we want to show to the user (Just change ListBox to ListView for Windows 8 in XAML):

<ListBox x:Name="PostListBox">
                <ListBox.ItemTemplate>
                    <DataTemplate>
				<StackPanel>
 				<Image x:Name="PostImage" 
				       Source="{Binding thumbnail}" />
                           	<TextBlock x:Name="TitleTextBlock" 
				           Text="{Binding title}" 
					   TextWrapping="Wrap" 
					   FontSize="20" />
                                <TextBlock x:Name="PublishedTextBlock" 
					   Text="{Binding date}" 
					   FontSize="12"/>
				</StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
          </ListBox>

As you can see, we have set some Bindings in the code above. This Bindings rely on the DataContract Post, as every ListBox/ListView-Item represents one Post of our postList.

[DataContract]
public class Post
    {
        [DataMember]
        public int id { get; set; }
        [DataMember]
        public string type { get; set; }
        [DataMember]
        public string slug { get; set; }
        [DataMember]
        public string url { get; set; }
        [DataMember]
        public string status { get; set; }
        [DataMember]
        public string title { get; set; }
        [DataMember]
        public string title_plain { get; set; }
        [DataMember]
        public string content { get; set; }
        [DataMember]
        public string excerpt { get; set; }
        [DataMember]
        public string date { get; set; }
        [DataMember]
        public string modified { get; set; }
        [DataMember]
        public List<Category> categories { get; set; }
        [DataMember]
        public List<object> tags { get; set; }
        [DataMember]
        public Author author { get; set; }
        [DataMember]
        public List<comment> comments { get; set; }
        [DataMember]
        public List<Attachment> attachments { get; set; }
        [DataMember]
        public int comment_count { get; set; }
        [DataMember]
        public string comment_status { get; set; }
        [DataMember]
        public string thumbnail { get; set; }
    }

Choose the fields you want to display to create your own DataTemplate to show only the data you want. Last but not least we have to tell our app that the ItemSource of our ListBox is the deserialized list, which is also done easily:

PostListBox.ItemsSource = postList.posts;

If you now hit F5 on your keyboard, the app should be built and the device/emulator should show your recent posts in a list. You don’t need to add additional code to download the images, as the image source points already to an image and will be downloaded automatically.

Pro-Tip:

The thumbnails from the our DataContract Post are looking really ugly sometimes. To get a better looking result in your ListBox/ListView, I recommend to use the attached images. To do this, you will need the following code:

          foreach (var item in postList.posts)
            {
                var postImagefromAttachement = item.attachments.FirstOrDefault();
                if (postImagefromAttachement == null)
                {
                    item.thumbnail = placeholderImage; //add your own placeholderimage here
                }
                else
                {
                    item.thumbnail = postImagefromAttachement.images.medium.url;
                }

            }

This code checks your list of attachments in your post, takes the first image, and downloads a higher quality (medium/full).  I am using medium to get best results on quality and download speed.

I hope this is helpful for some of you to get forward for to create a WordPress blog app on Windows Phone and Windows 8.

Happy coding!

Posted by msicc in Archive, 1 comment
Dev Story Series (Part 1 of many): Creating a data class for both Windows 8 and Windows Phone app

Dev Story Series (Part 1 of many): Creating a data class for both Windows 8 and Windows Phone app

As I promised earlier on my application for the Intel App Innovation Contest on codeproject.com, I will do a series of blog posts for my application MSicc´s Blog for Windows 8 and Windows Phone.

This is the first article in my new Dev Story Series, where I describe the development process of the app. I am starting with the very first steps that you have to do if you plan such an application. To make the application useful, we first have to decide how we want to get the data from our blog/website into our application.

One hint that will make some of you crying out loud: At the moment I am not using the MVVM pattern. I am aware of the fact that most devs for Silverlight/C# swear on it, but I still decided to go without it – as well on Windows Phone as on Windows 8. I will continue to learn it in one of my future project, but for the moment I just want to get things done – also if that means that I have to create some – well, let us call it “compromises”.

Which way to choose?

If you consider to create a “blog reader”, you have to think about how you want to get the data from your blog into your app. There are different ways:

  • via a RSS/Atom feed (that was in the old version of my Windows Phone app for msicc.net)
  • via XMLRPC (if your blog supports that)
  • via JSON

I decided to go with JSON for the new version. There were several reasons to do so:

  • there is an app err… an plugin for that on WordPress
  • JSON is fast
  • JSON is set to be the new standard for data consumption
  • With JSON.NET you can deserialize your data with only one line(!) of code

How do we get the data in our app?

Of course, we will download it. But if you only download your JSON data, the only thing you will get is a very weird looking string that looks like this:

json_string_unserialized

That´s pretty ugly, right? Of course we could work us through all arrays and objects there. That would take hours and hours until we would have covered all data we need for our apps. Luckily, there are two tools that make the whole thing a lot easier.

Two handy tools to make a dev´s life easier

The first tool I want to show you is “Beautify JSON”. It is a web based tool that makes strings like the one above readable for a human. Find it here.

Just paste the string of your JSON API in there, and you will get a readable version of your JSON string:

beautify_json

If you want to use only some of the data that your API provides, you can now easily search the string for the objects and arrays that you need.

If you quickly want to create a data class for all data that is provided, you can do this by using json2charp.  It provides a ready-to-use code that can easily be copied and pasted into your class file in Visual Studio:

json2charp

Now let´s have a look to the class itself:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace WordPressDataClass
{
 public class Posts
    {
        [DataMember]
        public string status { get; set; }
        [DataMember]
        public int count { get; set; }
        [DataMember]
        public int count_total { get; set; }
        [DataMember]
        public int pages { get; set; }
        [DataMember]
        public List<Post> posts { get; set; }
    }
}

As you can see, I created a DataContract and DataMember based class by using System.Runtime.Serialization. If you want to know more about DataContracts and DataMembers I recommend you to read MSDN: using Data Contracts.

I am not posting the whole class, only the key DataContract Posts, which will get us our List of posts. You can download the whole class at the end of the post. It will be very helpful if you want to create an app for your WordPress based blog.

I use the class in both my Windows 8 and my Windows Phone app without any differences. As you can see, If you are familiar with Windows Phone Development, there is only a small step to Windows 8 development.

I hope this article is helpful for some of you. In my next post I will show you how easily you can use the provided JSON Data in your app/s.

source code: JsonDataClass

Posted by msicc in Archive, 4 comments