<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Mythical Man Moth]]></title><description><![CDATA[Hi, I’m Pieter van der Westhuizen. I'm a professional freelance web & mobile developer from South Africa that has been code slinging for more than 23 years.
htt]]></description><link>https://mythicalmanmoth.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1664283040648/hk41iXQ1V.png</url><title>Mythical Man Moth</title><link>https://mythicalmanmoth.com</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 10 May 2026 09:27:09 GMT</lastBuildDate><atom:link href="https://mythicalmanmoth.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[A Study in Flutter: Dynamic Forms]]></title><description><![CDATA[A recent requirement came up for configurable dynamic forms in a mobile application. There are a few dynamic form packages for Flutter, but I wanted a bit more control over the schema and behavior of the form. Here follows my attempt at creating dyna...]]></description><link>https://mythicalmanmoth.com/a-study-in-flutter-dynamic-forms</link><guid isPermaLink="true">https://mythicalmanmoth.com/a-study-in-flutter-dynamic-forms</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Flutter Examples]]></category><category><![CDATA[dynamic forms]]></category><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Tue, 25 Jul 2023 16:48:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690288820195/13585d68-a798-4703-b2c8-3cf98a85f367.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A recent requirement came up for configurable dynamic forms in a mobile application. There are a few dynamic form packages for Flutter, but I wanted a bit more control over the schema and behavior of the form. Here follows my attempt at creating dynamic forms with Flutter.</p>
<h3 id="heading-the-json-schema">The JSON Schema</h3>
<p>The first challenge we have to solve is the JSON schema for the form. We need to be able to specify the list of fields for the form as well as the following for each field:</p>
<ul>
<li><p><strong>type</strong> - Text or a Dropdown list</p>
</li>
<li><p><strong>label</strong> - The label to display for the field e.g. Your Name</p>
</li>
<li><p><strong>key</strong> - An internal use id for the field</p>
</li>
<li><p><strong>validations</strong> - A list of validations for the field e.g. required, min/max length, etc</p>
</li>
</ul>
<p>The schema I came up with looks like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Contact Details Form"</span>,
  <span class="hljs-attr">"fields"</span>: [
    {
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"TextBox"</span>,
      <span class="hljs-attr">"label"</span>: <span class="hljs-string">"Full Name"</span>,
      <span class="hljs-attr">"key"</span>: <span class="hljs-string">"fullName"</span>,
      <span class="hljs-attr">"validations"</span>: {
        <span class="hljs-attr">"required"</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">"minLength"</span>: <span class="hljs-number">3</span>,
        <span class="hljs-attr">"maxLength"</span>: <span class="hljs-number">50</span>
      }
    },
    {
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"TextBox"</span>,
      <span class="hljs-attr">"label"</span>: <span class="hljs-string">"Email"</span>,
      <span class="hljs-attr">"key"</span>: <span class="hljs-string">"email"</span>,
      <span class="hljs-attr">"validations"</span>: {
        <span class="hljs-attr">"required"</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">"email"</span>: <span class="hljs-literal">true</span>
      }
    },
    {
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"TextBox"</span>,
      <span class="hljs-attr">"label"</span>: <span class="hljs-string">"Age"</span>,
      <span class="hljs-attr">"key"</span>: <span class="hljs-string">"age"</span>,
      <span class="hljs-attr">"validations"</span>: {
        <span class="hljs-attr">"required"</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">"numeric"</span>: <span class="hljs-literal">true</span>
      }
    },
    {
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"DropdownList"</span>,
      <span class="hljs-attr">"label"</span>: <span class="hljs-string">"Province"</span>,
      <span class="hljs-attr">"key"</span>: <span class="hljs-string">"province"</span>,
      <span class="hljs-attr">"options"</span>: [
        <span class="hljs-string">"Eastern Cape"</span>,
        <span class="hljs-string">"Free State"</span>,
        <span class="hljs-string">"Gauteng"</span>,
        <span class="hljs-string">"KwaZulu-Natal"</span>,
        <span class="hljs-string">"Limpopo"</span>,
        <span class="hljs-string">"Mpumalanga"</span>,
        <span class="hljs-string">"Northern Cape"</span>,
        <span class="hljs-string">"North West"</span>,
        <span class="hljs-string">"Western Cape"</span>
      ],
      <span class="hljs-attr">"validations"</span>: {<span class="hljs-attr">"required"</span>: <span class="hljs-literal">true</span>}
    }
  ]
}
</code></pre>
<h3 id="heading-validation-types">Validation Types</h3>
<p>Most of the properties are pretty self-explanatory, but let's take a closer look at the <strong>validations</strong> property. To keep things relatively simple, we'll only have 5 types of validations:</p>
<ul>
<li><p><strong>required</strong> - Whether the field is required or not.</p>
</li>
<li><p><strong>minLength</strong> - The minimum number of characters required.</p>
</li>
<li><p><strong>maxLength</strong> - The maximum number of allowed characters.</p>
</li>
<li><p><strong>email</strong> - The field must be a valid email address.</p>
</li>
<li><p><strong>numeric</strong> - The field must be a valid number.</p>
</li>
</ul>
<h3 id="heading-packages">Packages</h3>
<p>To make things a bit easier, I decided to use the <a target="_blank" href="https://pub.dev/packages/flutter_form_builder">flutter_form_builder</a> package as well as its companion <a target="_blank" href="https://pub.dev/packages/form_builder_validators">form_builder_validators</a> package.</p>
<p>The flutter_form_builder removes a lot of the boilerplate code needed for forms and the form_builder_validators package has a nice list of pre-built validators, which is perfect for our use case.</p>
<h3 id="heading-the-flutter-app">The Flutter App</h3>
<p>I won't bore you with the full details of creating the Flutter app, but will only focus on the key parts.</p>
<p><strong>The Home Screen</strong></p>
<p>The Home screen makes up the entirety of the app. It's made up of a Scaffold, whose body contains only a <strong><em>FutureBuilder,</em></strong> which is used to load the data for the form (I'm not using any state management package for this app)<strong><em>.</em></strong> It also has a <strong><em>FloatingActionButton</em></strong>, which we'll use to validate and save the form. The code listing for the HomeScreen follows:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomeScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-keyword">final</span> FormRepository formRepository;

  <span class="hljs-keyword">const</span> HomeScreen({
    <span class="hljs-keyword">super</span>.key,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.formRepository,
  });

  <span class="hljs-meta">@override</span>
  State&lt;HomeScreen&gt; createState() =&gt; _HomeScreenState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_HomeScreenState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">HomeScreen</span>&gt; </span>{
  <span class="hljs-keyword">final</span> GlobalKey&lt;FormBuilderState&gt; _formKey = GlobalKey&lt;FormBuilderState&gt;();

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(
        title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"Dynamic Forms"</span>),
      ),
      body: FutureBuilder&lt;DynamicForm?&gt;(
        future: widget.formRepository.loadForm(),
        builder: (BuildContext context, AsyncSnapshot&lt;DynamicForm?&gt; snapshot) {
          <span class="hljs-keyword">if</span> (snapshot.connectionState == ConnectionState.waiting) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">const</span> Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  CircularProgressIndicator(),
                  SizedBox(height: <span class="hljs-number">16</span>),
                  Text(<span class="hljs-string">"Loading form, please wait..."</span>),
                ],
              ),
            );
          }
          <span class="hljs-keyword">if</span> (snapshot.hasError) {
            <span class="hljs-keyword">return</span> Center(
              child: Text(<span class="hljs-string">"Something bad happened <span class="hljs-subst">${snapshot.error}</span>"</span>),
            );
          }
          <span class="hljs-keyword">if</span> (snapshot.hasData) {
            <span class="hljs-keyword">return</span> Padding(
              padding: <span class="hljs-keyword">const</span> EdgeInsets.all(<span class="hljs-number">16.0</span>),
              child: FormBuilder(
                key: _formKey,
                child: Column(
                  children: snapshot.data!.fields
                      .map(
                        (field) =&gt; DynamicFormInput(
                          field: field,
                        ),
                      )
                      .toList(),
                ),
              ),
            );
          }
          <span class="hljs-keyword">return</span> <span class="hljs-keyword">const</span> Center(child: Text(<span class="hljs-string">"Form does not exist."</span>));
        },
      ),
      floatingActionButton: FloatingActionButton(
        mini: <span class="hljs-keyword">true</span>,
        onPressed: () {
          <span class="hljs-keyword">if</span> (_formKey.currentState!.saveAndValidate(focusOnInvalid: <span class="hljs-keyword">false</span>)) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                backgroundColor: Colors.green,
                duration: <span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">10</span>),
                content: Text(
                  <span class="hljs-string">'Form successfully validated and saved. Form data: <span class="hljs-subst">${_formKey.currentState!.value}</span>'</span>,
                ),
              ),
            );
          } <span class="hljs-keyword">else</span> {
            ScaffoldMessenger.of(context).showSnackBar(
              <span class="hljs-keyword">const</span> SnackBar(
                backgroundColor: Colors.redAccent,
                content: Text(<span class="hljs-string">'Form validation failed'</span>),
              ),
            );
          }
        },
        child: <span class="hljs-keyword">const</span> Icon(Icons.save),
      ),
    );
  }
}
</code></pre>
<p>Nothing too extreme in the code above, let's focus on the part where the data has finished loading and we have a data snapshot to work with. Note, that we're using the <strong>FormBuilder</strong> widget from the <strong>flutter_form_builder</strong> package and setting its child to a <strong>Column</strong> widget.</p>
<p>Now, the real action starts when we populate the Column widget's children by mapping the <strong>fields</strong> properties of the <strong>DynamicForm</strong> class to a <strong>DynamicFormInput</strong> widget.</p>
<p><strong>The DynamicFormInput widget</strong></p>
<p>The DynamicFormInput widget accepts a <strong>DynamicFormField</strong> object as a constructor parameter. Based on the <strong>type</strong> property of the object, we then return a different type of form element from the <strong>flutter_form_builder</strong> package. The code is relatively straightforward, but the real beauty of the <strong>flutter_form_builder</strong> is shown when we get to the <strong>validator</strong> property of its widgets. You'll notice how we check the validations property of the <strong>DynamicFormField</strong> object and then add the necessary <strong>FormBuilderValidators</strong> as needed.</p>
<p>The code listing for the DynamicFormInput widget follows:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DynamicFormInput</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">final</span> DynamicFormField field;

  <span class="hljs-keyword">const</span> DynamicFormInput({
    <span class="hljs-keyword">super</span>.key,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.field,
  });

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">switch</span> (field.type) {
      <span class="hljs-keyword">case</span> <span class="hljs-string">'TextBox'</span>:
        <span class="hljs-keyword">return</span> Padding(
          padding: <span class="hljs-keyword">const</span> EdgeInsets.only(bottom: <span class="hljs-number">16.0</span>),
          child: FormBuilderTextField(
            autovalidateMode: AutovalidateMode.onUserInteraction,
            name: field.key,
            decoration: InputDecoration(labelText: field.label),
            keyboardType: _getInputType(
              field.validations.numeric,
              field.validations.email,
            ),
            validator: FormBuilderValidators.compose(
              [
                <span class="hljs-keyword">if</span> (field.validations.<span class="hljs-keyword">required</span>)
                  FormBuilderValidators.<span class="hljs-keyword">required</span>(errorText: <span class="hljs-string">'Required'</span>),
                <span class="hljs-keyword">if</span> (field.validations.email != <span class="hljs-keyword">null</span> &amp;&amp; field.validations.email == <span class="hljs-keyword">true</span>)
                  FormBuilderValidators.email(errorText: <span class="hljs-string">"A valid email is required"</span>),
                <span class="hljs-keyword">if</span> (field.validations.numeric != <span class="hljs-keyword">null</span> &amp;&amp; field.validations.numeric == <span class="hljs-keyword">true</span>)
                  FormBuilderValidators.numeric(errorText: <span class="hljs-string">"A number is required"</span>),
                <span class="hljs-keyword">if</span> (field.validations.minLength != <span class="hljs-keyword">null</span>)
                  FormBuilderValidators.minLength(field.validations.minLength!),
                <span class="hljs-keyword">if</span> (field.validations.maxLength != <span class="hljs-keyword">null</span>)
                  FormBuilderValidators.maxLength(field.validations.maxLength!),
              ],
            ),
          ),
        );

      <span class="hljs-keyword">case</span> <span class="hljs-string">'DropdownList'</span>:
        <span class="hljs-keyword">return</span> FormBuilderDropdown(
          autovalidateMode: AutovalidateMode.onUserInteraction,
          name: field.key,
          decoration: InputDecoration(labelText: field.label),
          items: field.options!
              .map&lt;DropdownMenuItem&lt;<span class="hljs-built_in">String</span>&gt;&gt;(
                (<span class="hljs-built_in">String</span> value) =&gt; DropdownMenuItem(
                  value: value,
                  child: Text(value),
                ),
              )
              .toList(),
          validator: FormBuilderValidators.compose([
            <span class="hljs-keyword">if</span> (field.validations.<span class="hljs-keyword">required</span>)
              FormBuilderValidators.<span class="hljs-keyword">required</span>(errorText: <span class="hljs-string">'Please make a selection'</span>),
          ]),
        );

      <span class="hljs-keyword">default</span>:
        <span class="hljs-keyword">return</span> Padding(
          padding: <span class="hljs-keyword">const</span> EdgeInsets.all(<span class="hljs-number">8.0</span>),
          child: Text(
            <span class="hljs-string">"Field Type [<span class="hljs-subst">${field.type}</span>] does not exist."</span>,
            style: <span class="hljs-keyword">const</span> TextStyle(
              color: Colors.redAccent,
              fontWeight: FontWeight.bold,
            ),
          ),
        );
    }
  }

  TextInputType _getInputType(<span class="hljs-built_in">bool?</span> numeric, <span class="hljs-built_in">bool?</span> email) {
    <span class="hljs-keyword">if</span> (numeric != <span class="hljs-keyword">null</span> &amp;&amp; numeric == <span class="hljs-keyword">true</span>) {
      <span class="hljs-keyword">return</span> TextInputType.number;
    }
    <span class="hljs-keyword">if</span> (email != <span class="hljs-keyword">null</span> &amp;&amp; email == <span class="hljs-keyword">true</span>) {
      <span class="hljs-keyword">return</span> TextInputType.emailAddress;
    }
    <span class="hljs-keyword">return</span> TextInputType.text;
  }
}
</code></pre>
<p><strong>The DynamicForm class</strong></p>
<p>We're using the <strong>DynamicForm</strong>, <strong>DynamicFormField</strong> and <strong>DynamicFormFieldValidation</strong> classes to give us a strongly-typed way to access the form data we receive from the <strong>FormRepository.</strong> There is nothing very special about these classes, I used the <a target="_blank" href="https://pub.dev/packages/json_serializable">json_serializable</a> package to help with the serialization/deserialization. If that's not your cup of tea, check the other branch on <a target="_blank" href="https://github.com/Pietervdw/flutter-dynamic-forms">the sample GitHub repo</a>, for an example without using it.</p>
<p>The code for the classes follows:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:json_annotation/json_annotation.dart'</span>;

<span class="hljs-keyword">part</span> <span class="hljs-string">'dynamic_form.g.dart'</span>;

<span class="hljs-meta">@JsonSerializable</span>()
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DynamicForm</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">int</span> id;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> name;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span>&lt;DynamicFormField&gt; fields;

  DynamicForm({
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.id,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.name,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.fields,
  });

  <span class="hljs-keyword">factory</span> DynamicForm.fromJson(<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; json) =&gt; _$DynamicFormFromJson(json);
  <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; toJson() =&gt; _$DynamicFormToJson(<span class="hljs-keyword">this</span>);
}
</code></pre>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:json_annotation/json_annotation.dart'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">'../domain_models.dart'</span>;

<span class="hljs-keyword">part</span> <span class="hljs-string">'dynamic_form_field.g.dart'</span>;

<span class="hljs-meta">@JsonSerializable</span>()
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DynamicFormField</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> type;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> label;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> key;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">String</span>&gt;? options;
  <span class="hljs-keyword">final</span> DynamicFormFieldValidation validations;

  DynamicFormField({
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.type,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.label,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.key,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.options,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.validations,
  });

  <span class="hljs-keyword">factory</span> DynamicFormField.fromJson(<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; json) =&gt; _$DynamicFormFieldFromJson(json);

  <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; toJson() =&gt; _$DynamicFormFieldToJson(<span class="hljs-keyword">this</span>);
}
</code></pre>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:json_annotation/json_annotation.dart'</span>;

<span class="hljs-keyword">part</span> <span class="hljs-string">'dynamic_form_field_validation.g.dart'</span>;

<span class="hljs-meta">@JsonSerializable</span>()
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DynamicFormFieldValidation</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">bool</span> <span class="hljs-keyword">required</span>;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">int?</span> minLength;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">int?</span> maxLength;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">bool?</span> email;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">bool?</span> numeric;

  DynamicFormFieldValidation({
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.<span class="hljs-keyword">required</span>,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.minLength,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.maxLength,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.email,
    <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.numeric,
  });

  <span class="hljs-keyword">factory</span> DynamicFormFieldValidation.fromJson(<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; json) =&gt; _$DynamicFormFieldValidationFromJson(json);
  <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">dynamic</span>&gt; toJson() =&gt; _$DynamicFormFieldValidationToJson(<span class="hljs-keyword">this</span>);
}
</code></pre>
<p><strong>The FormRepository</strong></p>
<p>You'll notice that the HomeScreen's FutureBuilder's <strong>future</strong> property is set to:</p>
<pre><code class="lang-dart">widget.formRepository.loadForm()
</code></pre>
<p>The FormRepository's <strong>loadForm</strong> method simulates loading the data from an API with a short delay and simply parses a JSON string and deserializes the JSON into a <strong>DynamicForm</strong> class and returns said object.</p>
<p>The full code for the <strong>FormRepository</strong> follows:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FormRepository</span> </span>{

  <span class="hljs-built_in">String</span> getJson() {
    <span class="hljs-built_in">String</span> json = <span class="hljs-string">'''{
  "id": 1,
  "name": "Contact Details Form",
  "fields": [
    {
      "type": "TextBox",
      "label": "Full Name",
      "key": "fullName",
      "validations": {
        "required": true,
        "minLength": 3,
        "maxLength": 50
      }
    },
    {
      "type": "TextBox",
      "label": "Email",
      "key": "email",
      "validations": {
        "required": true,
        "email": true
      }
    },
    {
      "type": "TextBox",
      "label": "Age",
      "key": "age",
      "validations": {
        "required": false,
        "numeric": true
      }
    },
    {
      "type": "DropdownList",
      "label": "Province",
      "key": "province",
      "options": [
        "Eastern Cape",
        "Free State",
        "Gauteng",
        "KwaZulu-Natal",
        "Limpopo",
        "Mpumalanga",
        "Northern Cape",
        "North West",
        "Western Cape"
      ],
      "validations": {"required": true}
    }
  ]
}'''</span>;
    <span class="hljs-keyword">return</span> json;
  }

  Future&lt;DynamicForm&gt; loadForm() <span class="hljs-keyword">async</span> {
    <span class="hljs-comment">// Simulate loading Time as if calling an API</span>
    <span class="hljs-keyword">await</span> Future.delayed(<span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">3</span>));
    <span class="hljs-keyword">final</span> dynamicForm = DynamicForm.fromJson(jsonDecode(getJson()));
    <span class="hljs-keyword">return</span> dynamicForm;
  }
}
</code></pre>
<p>That is basically it when it comes to this solution, there is a lot of room for improvement and enhancement, but I think this should be a pretty good starting point. Here is a short clip of how the forms validates:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=ODcUuSoi33I">https://www.youtube.com/watch?v=ODcUuSoi33I</a></div>
<p> </p>
<p>The full code for this example is available on <a target="_blank" href="https://github.com/Pietervdw/flutter-dynamic-forms">GitHub</a></p>
<p>Thank you for reading. Until next time, keep coding!</p>
]]></content:encoded></item><item><title><![CDATA[Introduction to CSharp2Dart.com]]></title><description><![CDATA[If you've ever written a mobile app with Flutter that integrates with an API, then you'll know that there are a lot of model objects that get passed between the app and the API.
JSON Serialization in Flutter can also take a fair amount of boilerplate...]]></description><link>https://mythicalmanmoth.com/introduction-to-csharp2dartcom</link><guid isPermaLink="true">https://mythicalmanmoth.com/introduction-to-csharp2dartcom</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Fri, 07 Jan 2022 12:52:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281627589/aH0FktLAn.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you've ever written a mobile app with Flutter that integrates with an API, then you'll know that there are a lot of model objects that get passed between the app and the API.</p>
<p>JSON Serialization in Flutter can also take a fair amount of boilerplate code in order to work and can feel somewhat tedious and repetitive. If you're building your API using C#, you'll also duplicate the same model structure in C# in order to receive the serialized models from Flutter and vice versa.</p>
<p>With this in mind, and to help remove some of the slog work, I've created https://www.csharp2dart.com/.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281619126/p1SUOIY0D.png" alt="A screenshot of the csharp2dart website" /></p>
<p>The site provides a simple interface where you can paste your C# code and then generate it's Dart equivalent. If the site looks somewhat familiar, I did take some inspiration from <a target="_blank" href="https://csharp2json.io/">https://csharp2json.io/</a></p>
<p>You'll have some control over the code that is generated by setting the following options:</p>
<p><strong>a) Add @JsonSerialization() annotation</strong>
This will add an import and part statement to the top of the file as well as decorate the class with the @JsonSerialization() annotation. e.g.:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281620558/2AEf3I6zD.png" alt="Json Serialization annotation screenshot" /> </p>
<p><strong>b) Add toJson() method</strong>
This option generates the <em>toJson()</em> method, which in turn will make it easy to serialize the object to JSON. The <a target="_blank" href="https://pub.dev/packages/json_serializable">json_serializable </a> package will generate this method for you and it can be found inside the generated <em>*.g.dart</em> file.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281622624/GR-6bVOOI.png" alt="toJson method screenshot" /> </p>
<p><strong>c) Add fromJson() method</strong>
This method does the inverse of the <em>toJson()</em> method. With this method you can create a new instance of your class from JSON. As with the <em>toJson()</em> method json_serializable does all the code generation.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281623857/y3B4VH3aS.png" alt="fromJson method screenshot" /></p>
<p><strong>d) All fields should be nullable</strong>
If you need all the fields of the Dart class to be nullable, setting this property will automatically do that for you.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281625147/12K2NE8nN.png" alt="Nullable fields option screenshot" /></p>
<p><strong>e) Required constructor parameters</strong>
The last option, if set, makes all the constructor parameters required.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281626437/EcffjtNCN.png" alt="Required constructor parameters screenshot" /></p>
<p>If you want to generate more than one class at a time, it is possible. For example, the following code:</p>
<pre><code class="lang-csharp">    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Product</span>
    {
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> ProductId { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }        
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Title { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }        
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> SubTitle { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }        
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">bool</span> IsActive { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-literal">true</span>;    
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ProductOption</span> 
    {        
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Title { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Price { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> QuantityInStock { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    }
</code></pre>
<p>will produce two Dart classes:</p>
<pre><code class="lang-dart"><span class="hljs-comment">// -- product.dart --</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Product</span> </span>{
    <span class="hljs-built_in">int</span> productId;
    <span class="hljs-built_in">String</span> title;
    <span class="hljs-built_in">String</span> subTitle;
    <span class="hljs-built_in">bool</span> isActive;

    Product(<span class="hljs-keyword">this</span>.productId,<span class="hljs-keyword">this</span>.title,<span class="hljs-keyword">this</span>.subTitle,<span class="hljs-keyword">this</span>.isActive,);
}
<span class="hljs-comment">// -- product_option.dart --</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductOption</span> </span>{
    <span class="hljs-built_in">String</span> title;
    <span class="hljs-built_in">double</span> price;
    <span class="hljs-built_in">int</span> quantityInStock;

    ProductOption(<span class="hljs-keyword">this</span>.title,<span class="hljs-keyword">this</span>.price,<span class="hljs-keyword">this</span>.quantityInStock,);
}
</code></pre>
<p>Please feel free to use it and if you run into any bugs or want to suggest any new feature, please create a new <a target="_blank" href="https://github.com/Coalition-Software/csharp2dart-issues">GitHub issue</a>.</p>
<p>Thank you for reading. Until next time, keep coding!</p>
<p> -P</p>
<blockquote>
<p>P.S. To learn more about JSON and serialization in Flutter, please see the <a target="_blank" href="https://docs.flutter.dev/development/data-and-backend/json">Flutter documentation</a>.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Searching Azure Blob Storage using Blob Index]]></title><description><![CDATA[Back in May 2020, Microsoft announced a new feature for Azure Blob Storage called Blob Index. Essentially, this enables you to add key/value tags to your Blob objects and be able to query said Blob objects without having to use a separate service lik...]]></description><link>https://mythicalmanmoth.com/searching-azure-blob-storage-using-blob-index</link><guid isPermaLink="true">https://mythicalmanmoth.com/searching-azure-blob-storage-using-blob-index</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Mon, 19 Apr 2021 11:41:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281637377/2lgdRz0T3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Back in May 2020, Microsoft announced a new feature for Azure Blob Storage called Blob Index. Essentially, this enables you to add key/value tags to your Blob objects and be able to query said Blob objects without having to use a separate service like Azure Search.</p>
<p>This is great because in many instances you'd only want to store a few additional properties for your Blob objects and still be able to query on theses properties without having to create and maintain a separate database that does this for you (or setup something like Azure Search)</p>
<p>Now, bear in mind this is still in Preview and the features can still change and there are also a few limitations to consider (<a href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-manage-find-blobs?tabs=azure-portal">source</a>):</p>
<ul>
<li>Each blob can have up to 10 blob index tags</li>
<li>Tag keys must be between one and 128 characters</li>
<li>Tag values must be between zero and 256 characters</li>
<li>Tag keys and values are case-sensitive</li>
<li>Tag keys and values only support string data types. Any numbers, dates, times, or special characters are saved as strings</li>
<li>Tag keys and values must adhere to the following naming rules:<ul>
<li>Alphanumeric characters:<ul>
<li><strong>a</strong> through <strong>z</strong> (lowercase letters)</li>
<li><strong>A</strong> through <strong>Z</strong> (uppercase letters)</li>
<li><strong>0</strong> through <strong>9</strong> (numbers)</li>
</ul>
</li>
<li>Valid special characters: space, plus, minus, period, colon, equals, underscore, forward slash (<code>+-.:=_/</code>)</li>
</ul>
</li>
</ul>
<p>With that said, I was excited to try this out, so in this post I'll show you how you can search your Azure Blob Storage files using Blob Index and C#.</p>
<h2 id="heading-the-console-app">The Console App</h2>
<p>We'll create a simple .NET Core Console Application to upload a few files to Azure Blob Storage, with some tags and then search them. I'm not going to take you through the process of creating the Console Application, but if you get stuck on this, let me know in the comments.</p>
<p>After  you've created the Console Application, add the [Azure.Storage.Blobs NuGet package] (https://www.nuget.org/packages/Azure.Storage.Blobs)  and create a new class called <strong>StorageService</strong>. This class will have the following two methods:</p>
<ol>
<li><em>UploadFile</em>, which is a simple class to upload a file and associate some tags with it.</li>
<li><em>FindCustomerFiles</em>, will return a list of Blob objects associated with a customer or a tag called Customer.</li>
</ol>
<h2 id="heading-uploading-azure-blob-objects">Uploading Azure Blob objects</h2>
<p>The code for the <strong>UploadFile</strong> method follows:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">UploadFile</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> containerName, <span class="hljs-keyword">string</span> filePath, Dictionary&lt;<span class="hljs-keyword">string</span>, <span class="hljs-keyword">string</span>&gt; tags</span>)</span>
{
    <span class="hljs-keyword">string</span> fileName = Path.GetFileName(filePath);
    BlobContainerClient container = _client.GetBlobContainerClient(containerName);
    BlobClient blob = container.GetBlobClient(fileName);

    <span class="hljs-keyword">using</span> FileStream fileStream = File.OpenRead(filePath);
    <span class="hljs-keyword">await</span> blob.UploadAsync(fileStream, <span class="hljs-literal">false</span>);
    fileStream.Close();
    <span class="hljs-keyword">await</span> blob.SetTagsAsync(tags);
}
</code></pre>
<p>You'll notice the method does not do anything spectacularly different than usually when uploading files to Azure Blob storage, however, take a look at the <strong>.SetTagsAsync</strong> method on the <strong>BlobClient</strong> object. This method take a Dictionary object containing all the tags we want to associate with the Blob object.</p>
<p>To upload files, we'll call the <strong>UploadFile</strong> method as illustrated below:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">UploadFile</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> filePath</span>)</span>
{
    <span class="hljs-keyword">string</span> accountName = <span class="hljs-string">"&lt;your-account-name&gt;"</span>;
    <span class="hljs-keyword">string</span> accountKey = <span class="hljs-string">"&lt;your-account-key&gt;"</span>;

    <span class="hljs-keyword">var</span> storageService = <span class="hljs-keyword">new</span> StorageService(accountName, accountKey);

    Dictionary&lt;<span class="hljs-keyword">string</span>, <span class="hljs-keyword">string</span>&gt; tags1 = <span class="hljs-keyword">new</span> Dictionary&lt;<span class="hljs-keyword">string</span>, <span class="hljs-keyword">string</span>&gt;
    {
        {<span class="hljs-string">"customer"</span>, <span class="hljs-string">"Acme Inc."</span>}, 
        {<span class="hljs-string">"product"</span>, <span class="hljs-string">"Anvil"</span>}
    };
    <span class="hljs-keyword">await</span> storageService.UploadFile(<span class="hljs-string">"files"</span>, filePath, tags1);
}
</code></pre>
<p>The code above creates a new instance of the <strong>StorageService</strong> class and passes in the Azure Blob Storage account name and key as constructor parameters. Next, we create  a new Dictionary object containing two tags called <em>customer</em> and <em>product</em>. Lastly, we upload the file to a Blob container called <em>files</em>. (The full code listing for the <strong>StorageService</strong> class is available at the bottom of this post.)</p>
<p>After uploading a few files using the <strong>UploadFile</strong> method, we should see them inside our <em>files</em> Blob Container, e.g.:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281633049/DJ_ehf99f.png" alt="File listing in Azuer Storage Explorer" /></p>
<p>We're using the Microsoft Azure Storage Explorer to view these files. If you do not already have it installed, get it <a href="https://azure.microsoft.com/en-us/features/storage-explorer/">here</a>.</p>
<p>To test whether our code worked, right-click on a file and select <strong>Edit Tags...</strong>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281634463/PoYPXocUv.png" alt="The Edit Tags option" /></p>
<p>You should see a list of tags associated with the Blob object:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281635960/p5mfR5RM7.png" alt="All tags associated with the object" /></p>
<h2 id="heading-searching-for-azure-blob-objects">Searching for Azure Blob objects</h2>
<p>The <strong>FindCustomerFiles</strong> method will perform a relatively simple search that will return any Blob objects in a specified container with a "customer" tag containing the supplied customer name. The code for the method follows:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;List&lt;TaggedBlobItem&gt;&gt; FindCustomerFiles(<span class="hljs-keyword">string</span> customerName, <span class="hljs-keyword">string</span> containerName = <span class="hljs-string">""</span>)
{
    <span class="hljs-keyword">var</span> foundItems = <span class="hljs-keyword">new</span> List&lt;TaggedBlobItem&gt;();
    <span class="hljs-keyword">string</span> searchExpression = <span class="hljs-string">$"\"customer\"='<span class="hljs-subst">{customerName}</span>'"</span>;
    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">string</span>.IsNullOrEmpty(containerName))
        searchExpression = <span class="hljs-string">$"@container = '<span class="hljs-subst">{containerName}</span>' AND \"customer\" = '<span class="hljs-subst">{customerName}</span>'"</span>;

    <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> page <span class="hljs-keyword">in</span> _client.FindBlobsByTagsAsync(searchExpression).AsPages())
    {
        foundItems.AddRange(page.Values);
    }
    <span class="hljs-keyword">return</span> foundItems;
}
</code></pre>
<p>The most important part of the <strong>FindCustomerFiles</strong> method is the <a href="https://docs.microsoft.com/en-us/dotnet/api/azure.storage.blobs.blobserviceclient.findblobsbytagsasync?view=azure-dotnet"><strong>FindBlobsByTagsAsync</strong></a> method on the <strong>BlobServiceClient</strong> object. It takes an ANSI SQL WHERE clause parameter and supports the following operators =, &gt;, &gt;=, &lt;, &lt;=, AND. Note that it will return ALL Blobs in the storage account that match the search expression, if you want to limit the results to a particular Blob container add @container to the search expression.</p>
<p>To use the <strong>FindCustomerFiles</strong> method to find all Blobs associated with customer <em>Acme Inc.</em> in the <em>files</em> Blob container, you'll use the following code:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">FindFiles</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">string</span> accountName = <span class="hljs-string">"&lt;your-account-name&gt;"</span>;
    <span class="hljs-keyword">string</span> accountKey = <span class="hljs-string">"&lt;your-account-key&gt;"</span>;

    <span class="hljs-keyword">var</span> storageService = <span class="hljs-keyword">new</span> StorageService(accountName, accountKey);
    <span class="hljs-keyword">var</span> files = <span class="hljs-keyword">await</span> storageService.FindCustomerFiles(customerName: <span class="hljs-string">"Acme Inc."</span>, containerName: <span class="hljs-string">"files"</span>);
    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> file <span class="hljs-keyword">in</span> files)
    {
        Console.WriteLine(file.BlobName);
    }
}
</code></pre>
<h3 id="heading-storageservice-code-listing">StorageService code listing</h3>
<p>The full code for the <strong>StorageService</strong> class follows:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">StorageService</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> BlobServiceClient _client;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">StorageService</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> accountName, <span class="hljs-keyword">string</span> accountKey</span>)</span>
    {
        <span class="hljs-keyword">var</span> connectionString = <span class="hljs-string">$"DefaultEndpointsProtocol=https;AccountName=<span class="hljs-subst">{accountName}</span>;AccountKey=<span class="hljs-subst">{accountKey}</span>;EndpointSuffix=core.windows.net"</span>;
        _client = <span class="hljs-keyword">new</span> BlobServiceClient(connectionString);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">UploadFile</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> containerName, <span class="hljs-keyword">string</span> filePath, Dictionary&lt;<span class="hljs-keyword">string</span>, <span class="hljs-keyword">string</span>&gt; tags</span>)</span>
    {
        <span class="hljs-keyword">string</span> fileName = Path.GetFileName(filePath);
        BlobContainerClient container = _client.GetBlobContainerClient(containerName);
        BlobClient blob = container.GetBlobClient(fileName);

        <span class="hljs-keyword">using</span> FileStream fileStream = File.OpenRead(filePath);
        <span class="hljs-keyword">await</span> blob.UploadAsync(fileStream, <span class="hljs-literal">false</span>);
        fileStream.Close();
        <span class="hljs-keyword">await</span> blob.SetTagsAsync(tags);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;List&lt;TaggedBlobItem&gt;&gt; FindCustomerFiles(<span class="hljs-keyword">string</span> customerName, <span class="hljs-keyword">string</span> containerName = <span class="hljs-string">""</span>)
    {
        <span class="hljs-keyword">var</span> foundItems = <span class="hljs-keyword">new</span> List&lt;TaggedBlobItem&gt;();
        <span class="hljs-keyword">string</span> searchExpression = <span class="hljs-string">$"\"customer\"='<span class="hljs-subst">{customerName}</span>'"</span>;
        <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">string</span>.IsNullOrEmpty(containerName))
            searchExpression = <span class="hljs-string">$"@container = '<span class="hljs-subst">{containerName}</span>' AND \"customer\" = '<span class="hljs-subst">{customerName}</span>'"</span>;

        <span class="hljs-keyword">await</span> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> page <span class="hljs-keyword">in</span> _client.FindBlobsByTagsAsync(searchExpression).AsPages())
        {
            foundItems.AddRange(page.Values);
        }
        <span class="hljs-keyword">return</span> foundItems;
    }
}
</code></pre>
<p>I hope you can see the same potential for this as I can and how easy it is to add a simple and quick file search to your Azure Blob Storage solutions.</p>
<p>Thank you for reading! Until next time, keep coding!</p>
]]></content:encoded></item><item><title><![CDATA[Using AWS Cognito with Vue/NuxtJS]]></title><description><![CDATA[In my last post, "Using AWS Cognito with Xamarin Forms", I showed how to authenticate with Amazon Cognito using Xamarin Forms and the Xamarin.Essentials Web Authenticator.
In this post, we'll go through the process of using the AWS Cognito Hosted UI ...]]></description><link>https://mythicalmanmoth.com/using-aws-cognito-with-vuenuxtjs</link><guid isPermaLink="true">https://mythicalmanmoth.com/using-aws-cognito-with-vuenuxtjs</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Tue, 06 Apr 2021 07:16:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664283439384/eyqGDFQTB.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my last post, <a target="_blank" href="https://dev.to/pietervdw/using-aws-cognito-with-xamarin-forms-46l5">"Using AWS Cognito with Xamarin Forms"</a>, I showed how to authenticate with Amazon Cognito using Xamarin Forms and the <a target="_blank" href="https://docs.microsoft.com/en-us/xamarin/essentials/web-authenticator">Xamarin.Essentials Web Authenticator</a>.</p>
<p>In this post, we'll go through the process of using the AWS Cognito Hosted UI with your own Vue/NuxtJS site. For an idea on the final result, please take a look at the <a target="_blank" href="https://www.youtube.com/watch?v=SiqARdvdpdk">YouTube Video</a></p>
<h1 id="heading-setting-up-an-aws-cognito-user-pool">Setting up an AWS Cognito user pool</h1>
<p>We'll be using the same AWS Cognito User pool and App client that we've created in my previous post. Please refer to the instructions details therein.</p>
<h1 id="heading-creating-the-vuenuxt-project">Creating the Vue/Nuxt project</h1>
<p>To create the Nuxt project, open up your preferred terminal window and enter the following command:</p>
<pre><code class="lang-console">yarn create nuxt-app mynuxtapp
</code></pre>
<p>When prompted, you can select the following options:</p>
<ol>
<li>Project name: <strong>mynuxtapp</strong></li>
<li>Programming language: <strong>JavaScript</strong></li>
<li>Package manager: <strong>Yarn</strong></li>
<li>UI framework: <strong>Vuetify.js</strong></li>
<li>Nuxt.js modules: <strong>Axios</strong></li>
<li>Rendering mode: <strong>Single Page App</strong></li>
<li>Deployment target: <strong>Static (Static/Jamstack hosting)</strong></li>
</ol>
<blockquote>
<p>I've assumed you've already installed everything necessary to create Vue/Nuxt projects. If not, please refer to the <a target="_blank" href="https://nuxtjs.org/docs/2.x/get-started/installation">NuxtJS documentation</a></p>
</blockquote>
<h2 id="heading-adding-the-nuxtauth-dependency">Adding the nuxt/auth dependency</h2>
<p>Add the nuxt/auth dependency to you project by executing the following command:</p>
<pre><code class="lang-console">yarn add --exact @nuxtjs/auth-next
</code></pre>
<p>Next, in the <strong>nuxt.config.js</strong> file, add the nuxt/auth module to the <strong>modules</strong> array.</p>
<pre><code class="lang-json">  modules: [
    <span class="hljs-string">"@nuxtjs/axios"</span>,
    <span class="hljs-string">"@nuxtjs/auth-next"</span>
  ],
</code></pre>
<p>While we have the <strong>nuxt.config.js</strong> file open, also add the <strong>auth</strong> section as below:</p>
<pre><code class="lang-json">  auth: {
    strategies: {
      awsCognito: {
        scheme: <span class="hljs-string">"oauth2"</span>,
        endpoints: {
          authorization: <span class="hljs-string">"https://myxamarinapp.auth.us-east-1.amazoncognito.com/login"</span>,
          token: <span class="hljs-string">"https://myxamarinapp.auth.us-east-1.amazoncognito.com/oauth2/token"</span>,
          userInfo: <span class="hljs-string">"https://myxamarinapp.auth.us-east-1.amazoncognito.com/oauth2/userInfo"</span>,
          logout: <span class="hljs-string">"https://myxamarinapp.auth.us-east-1.amazoncognito.com/logout"</span>
        },
        token: {
          property: <span class="hljs-string">"access_token"</span>,
          type: <span class="hljs-string">"Bearer"</span>,
          maxAge: <span class="hljs-number">3600</span>
        },
        refreshToken: {
          property: <span class="hljs-string">"refresh_token"</span>,
          maxAge: <span class="hljs-number">60</span> * <span class="hljs-number">60</span> * <span class="hljs-number">24</span> * <span class="hljs-number">30</span>
        },
        responseType: <span class="hljs-string">"token"</span>,
        redirectUri: <span class="hljs-string">"http://localhost:3000/login"</span>,
        logoutRedirectUri: <span class="hljs-string">"http://localhost:3000/login"</span>,
        clientId: <span class="hljs-string">"4jlfe2iki0ucn32uc44clmib3d"</span>,
        scope: [<span class="hljs-string">"email"</span>, <span class="hljs-string">"openid"</span>, <span class="hljs-string">"profile"</span>],
        codeChallengeMethod: <span class="hljs-string">"S256"</span>
      }
    }
  }
</code></pre>
<p>We're using the built-in OAuth2 scheme and we're calling it <strong>awsCognito</strong>. The endpoints are:</p>
<p><strong>authorization</strong>
This is the domain/url we've configured in AWS Cognito with <em>/login</em> appended. This loads the login page.</p>
<p><strong>token</strong>
This is the domain/url we've configured in AWS Cognito with <em>/oauth2/token</em> appended. This endpoint is used to get the user's tokens.</p>
<p><strong>userInfo</strong>
This is the domain/url we've configured in AWS Cognito with <em>/oauth2/userInfo</em> appended. This endpoint is used to retrieve information about the authenticated user.</p>
<p><strong>logout</strong>
This is the domain/url we've configured in AWS Cognito with <em>/logout</em> appended. Used to sign the user out.</p>
<blockquote>
<p>For more detail regarding these endpoints, please refer to the <a target="_blank" href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-userpools-server-contract-reference.html">Amazon Cognito user pools Auth API Reference</a></p>
</blockquote>
<p>The rest of the <strong>auth</strong> options should be relatively self-explanatory. For this example the important config entries are:</p>
<p><strong>response_type</strong>
Set this to <em>token</em> to inform AWS Cognito that we want an access_token back.</p>
<p><strong>redirectUri</strong>
This value should also be added to the list of Callback URL(s) under <strong>App integration &gt; App client settings</strong> in AWS Cognito. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664283434808/MFSLVSXYH.png" alt="image" /></p>
<p><strong>clientId</strong>
Is the same Client Id as configured in AWS Cognito. You'll find this under <strong>General settings &gt; App clients</strong>
 <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664283436225/hOYwAGiGQ.png" alt="image" /></p>
<p><strong>codeChallengeMethod</strong>
Amazon Cognito authentication server only support S256. This value must be supplied for the nuxt/auth OAuth scheme to work or else you'll receive a "unsupported code challenge method" error.</p>
<p>The last change we need to make in the <strong>nuxt.config.js</strong> file is to enable the auth middleware globally. Do this by setting the router middleware, as show below:</p>
<pre><code class="lang-json"> router: {
    middleware: [<span class="hljs-string">"auth"</span>]
  }
</code></pre>
<h2 id="heading-ui-changes">UI Changes</h2>
<p><strong><em>Login Page</em></strong>
We'll add a simple <strong>login page</strong>, inside the <strong>pages</strong> folder, called login.vue. The page will prompt the user to log in if they are not authenticated.  I contains a simple <em>login</em> method that logs in using the <strong>awsCognito</strong> scheme we've configured in the previous step, the code for the method follows:</p>
<pre><code class="lang-javascript">methods: {
    login() {
      <span class="hljs-built_in">this</span>.$auth.loginWith(<span class="hljs-string">"awsCognito"</span>);
    }
  }
</code></pre>
<p>The full code listing for the login page are:</p>
<pre><code class="lang-vue">&lt;template&gt;
  &lt;v-row align="center" justify="center"&gt;
    &lt;v-col cols="12" sm="8" md="4"&gt;
      &lt;v-card class="elevation-12" v-if="loggedIn"&gt;
        &lt;v-card-title&gt;Logging in.&lt;/v-card-title&gt;
        &lt;v-card-text
          &gt;Logging in, please wait...
          &lt;v-progress-circular indeterminate color="green"&gt;&lt;/v-progress-circular&gt;
        &lt;/v-card-text&gt;
      &lt;/v-card&gt;
      &lt;v-card class="elevation-12" v-else&gt;
        &lt;v-card-title&gt;You're not logged in&lt;/v-card-title&gt;
        &lt;v-card-text&gt;Click the button to log into your account. &lt;/v-card-text&gt;
        &lt;v-card-actions&gt;
          &lt;v-btn @click="login" color="primary"&gt;Login&lt;/v-btn&gt;
        &lt;/v-card-actions&gt;
      &lt;/v-card&gt;
    &lt;/v-col&gt;
  &lt;/v-row&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  layout: "unauthorized",
  data() {
    return {
      loggedIn: false
    };
  },
  created() {
    this.loggedIn = this.$auth.strategy.token.get();
  },
  methods: {
    login() {
      this.$auth.loginWith("awsCognito");
    }
  }
};
&lt;/script&gt;
</code></pre>
<p>In the page template we use <strong>v-if</strong> and <strong>v-else</strong> directives to either show a login button or a message informing the user that they are being logged in. This is useful when AWS Cognito redirects to the login page after the user has logged in.</p>
<p><strong><em>Home Page</em></strong>
The home page is located in the pages/index.vue file. This file should've been automatically added for you when you've created the project. This page will only be shown once the user is authenticated and will display some of the user's information as illustrated in the following image:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664283438041/fSZgzoTrK4.png" alt="image" /></p>
<p>There is not much logic in the page. The most important aspects is that we show the user information using properties on the <strong>this.$auth.user</strong> object and the logOut method uses <strong>this.$auth.logout()</strong> to log the user out when the "Log Out" button is clicked. </p>
<p>The full code listing for the page follows:</p>
<pre><code class="lang-vue">&lt;template&gt;
  &lt;v-row justify="center" align="center"&gt;
    &lt;v-col cols="12" sm="8" md="6"&gt;
      &lt;div class="text-center"&gt;
        &lt;logo /&gt;
        &lt;vuetify-logo /&gt;
      &lt;/div&gt;
      &lt;v-card&gt;
        &lt;v-card-title class="headline"&gt; Welcome {{ username }}, you are logged in! &lt;/v-card-title&gt;
        &lt;v-card-text&gt;
          &lt;p&gt;
            Here are your user details, retrieved from the
            &lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/userinfo-endpoint.html"&gt;/USERINFO&lt;/a&gt;
            endpoint:
          &lt;/p&gt;
          &lt;template&gt;
            &lt;v-simple-table&gt;
              &lt;template v-slot:default&gt;
                &lt;thead&gt;
                  &lt;tr&gt;
                    &lt;th class="text-left"&gt;
                      Property
                    &lt;/th&gt;
                    &lt;th class="text-left"&gt;
                      Value
                    &lt;/th&gt;
                  &lt;/tr&gt;
                &lt;/thead&gt;
                &lt;tbody&gt;
                  &lt;tr&gt;
                    &lt;td&gt;Email&lt;/td&gt;
                    &lt;td&gt;{{ email }}&lt;/td&gt;
                  &lt;/tr&gt;
                  &lt;tr&gt;
                    &lt;td&gt;Phone number&lt;/td&gt;
                    &lt;td&gt;{{ phoneNumber }}&lt;/td&gt;
                  &lt;/tr&gt;
                  &lt;tr&gt;
                    &lt;td&gt;UserId/sub&lt;/td&gt;
                    &lt;td&gt;{{ userId }}&lt;/td&gt;
                  &lt;/tr&gt;
                  &lt;tr&gt;
                    &lt;td&gt;User name&lt;/td&gt;
                    &lt;td&gt;{{ username }}&lt;/td&gt;
                  &lt;/tr&gt;
                  &lt;tr&gt;
                    &lt;td&gt;Access Token&lt;/td&gt;
                    &lt;td&gt;{{ accessToken }}&lt;/td&gt;
                  &lt;/tr&gt;
                  &lt;tr&gt;
                    &lt;td&gt;Refresh Token&lt;/td&gt;
                    &lt;td&gt;{{ refreshToken }}&lt;/td&gt;
                  &lt;/tr&gt;
                &lt;/tbody&gt;
              &lt;/template&gt;
            &lt;/v-simple-table&gt;
          &lt;/template&gt;
        &lt;/v-card-text&gt;
        &lt;v-card-actions&gt;
          &lt;v-spacer /&gt;
          &lt;v-btn color="primary" @click="logOut"&gt;
            Log Out
          &lt;/v-btn&gt;
        &lt;/v-card-actions&gt;
      &lt;/v-card&gt;
    &lt;/v-col&gt;
  &lt;/v-row&gt;
&lt;/template&gt;

&lt;script&gt;
import Logo from "~/components/Logo.vue";
import VuetifyLogo from "~/components/VuetifyLogo.vue";

export default {
  components: {
    Logo,
    VuetifyLogo
  },
  data() {
    return {
      email: null,
      phoneNumber: null,
      userId: null,
      username: null,
      accessToken: null,
      refreshToken: null
    };
  },
  created() {
    this.email = this.$auth.user.email;
    this.phoneNumber = this.$auth.user.phone_number;
    this.userId = this.$auth.user.sub;
    this.username = this.$auth.user.username;
    this.accessToken = this.$auth.strategy.token.get();
    this.refreshToken = this.$auth.strategy.refreshToken.get();
  },
  methods: {
    logOut() {
      this.$auth.logout();
    }
  }
};
&lt;/script&gt;
</code></pre>
<blockquote>
<p><strong>Note:</strong> I've explicitly shown on the page that the Refresh Token's value is false. This is because that AWS Cognito only returns refresh tokens if the <strong>Authorization Code</strong> grant is used. You can read more about refresh token in the <a target="_blank" href="https://developer.amazon.com/docs/login-with-amazon/refresh-token.html">Amazon Developer docs</a>.</p>
</blockquote>
<p>If everything goes according to plan, you should see a program flow similar to the video at the top of this post. I hope this post has been informative and that it can help you get started with Vue/Nuxt and Amazon Cognito.</p>
<p>Thank you for reading. Until next time, keep coding!</p>
<p>Full source code is available on GitHub: <a target="_blank" href="https://github.com/Pietervdw/vuenuxt-awscognito">https://github.com/Pietervdw/vuenuxt-awscognito</a></p>
]]></content:encoded></item><item><title><![CDATA[Using AWS Cognito with Xamarin Forms]]></title><description><![CDATA[In this post, I'll show you how to quickly and easily set up user authentication for your Xamarin Forms app using Amazon Cognito.
AWS Cognito is a user identity management solution by Amazon. It is a really easy way to add authentication to your appl...]]></description><link>https://mythicalmanmoth.com/using-aws-cognito-with-xamarin-forms</link><guid isPermaLink="true">https://mythicalmanmoth.com/using-aws-cognito-with-xamarin-forms</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Wed, 24 Mar 2021 08:43:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281665712/Ut0NqXASr.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this post, I'll show you how to quickly and easily set up user authentication for your <a href="https://dotnet.microsoft.com/apps/xamarin/xamarin-forms">Xamarin Forms</a> app using <a href="https://aws.amazon.com/cognito">Amazon Cognito</a>.</p>
<p><strong>AWS Cognito</strong> is a user identity management solution by Amazon. It is a really easy way to add authentication to your application without having to worry about building and managing your own identity/authentication solution.</p>
<p><strong>Xamarin Forms</strong> is an open-source cross-platform framework that you can use to create applications for Android, iOS and Windows.</p>
<h2 id="heading-setting-up-an-aws-cognito-user-pool">Setting up an AWS Cognito user pool</h2>
<p>First, we will need to create a user pool in AWS Cognito, which we'll use to create users and an <strong>App client</strong>. Head over to your <a href="https://console.aws.amazon.com/cognito">AWS Cognito console</a> and click on the <strong>"Manage User Pools"</strong> button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281642975/fNhZYHaMM.png" alt="image" /></p>
<p>Click the <strong>"Create a user pool"</strong> button, in the top-right corner of the next page. Next, enter a name for and choose the <strong>"Review defaults"</strong> option
 <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281644511/UAA1o03vP.png" alt="image" /></p>
<p>On the next page, you can review the default options (I'll leave you to experiment with the different settings on your own) and scroll down to <strong>App clients</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281645954/epBLqwA8l.png" alt="image" /></p>
<p>Click on the "Add app client..." link and on the next page, click <strong>"Add an app client"</strong>.</p>
<p>Next, only enter an <strong>App client name</strong> (We'll use "My Xamarin App" and keep all the options with their default values, scroll down and click <strong>"Create app client"</strong>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281647439/EDqUxc_Qv.png" alt="image" /></p>
<p>Click the <strong>"Return to pool details"</strong> and finally click on the <strong>"Create pool"</strong> button.</p>
<h2 id="heading-creating-a-new-user">Creating a new user</h2>
<p>Before we can log in, we first need to create a user. To do this, click on <strong>Users and groups</strong> under General settings and click the <strong>"Create user"</strong> button.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281650020/Z3dcGqlZFF.png" alt="image" />
Complete the form, by entering a valid email address (This will be needed shortly) and make sure to tick the <strong>Send an invitation to this new user?</strong> and <strong>Email</strong> checkboxes.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281651394/4EpqOyKTL.png" alt="image" /></p>
<p>With the user created, we need to configure the App client to allow the user to sign in.</p>
<h2 id="heading-configuring-the-app-client">Configuring the App client</h2>
<p>Click on <strong>App client settings</strong> under <strong>App integration</strong>.  Check the <em>Cognito User Pool</em> checkbox and complete the <em>Callback URL(s)</em> and <strong>Sign out URL(s)</strong>. These can be any valid web address for now, we'll change them a bit later on for use with our Xamarin app.</p>
<p>Next, check the <strong>Implicit grant</strong> OAuth flow and select the <strong>email</strong>, <strong>openid</strong> and <strong>profile</strong> OAuth scopes (The scopes won't be super important for this demo, but is when you integrate with your own API, etc.)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281652828/Yj3dhHeuTJ.png" alt="image" /></p>
<h2 id="heading-choose-a-domain-name">Choose a domain name</h2>
<p>With the App client configured, you need to choose a domain name. Click on <strong>Doman name</strong> under <strong>App integration</strong> and enter any domain prefix  you prefer and check if it is available by clicking on the <strong>Check availability</strong> button.</p>
<p>If your domain name is available, save the changes, and move onto customizing the UI for the sign-in page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281654308/aKDk8wXUJ.png" alt="Image3" /></p>
<h2 id="heading-customizing-the-sign-in-ui">Customizing the sign-in UI</h2>
<p>Customizing the UI is an optional step, but it is a nice way to make the UI fit in with your color scheme. Not much need to change with the default style, the only change is to add a custom logo.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281655740/Dorf1vvTl.png" alt="image" /></p>
<h2 id="heading-testing-the-sign-in-ui">Testing the sign-in UI</h2>
<p>Save your changes and head back to <strong>App client settings</strong> where you will notice that we now have the <strong>Launch Hosted UI</strong> link at the bottom of the page:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281657112/O6j4qDnj1.png" alt="image" /></p>
<p>Clicking on the <strong>Launch Hosted UI</strong> link will open the sign-in page in a separate browser tab and you should see something similar to the following:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281658509/3J1ui8M9Jv.png" alt="image" /> </p>
<p>Go ahead and sign in using the credentials for the user we have created earlier. You'll be prompted to specify a new password, remember this password as we'll use it shortly to log in via our Xamarin app.</p>
<h2 id="heading-the-xamarin-forms-app">The Xamarin Forms App</h2>
<p>I'm not going to walk you through the process of creating the Xamarin Forms app as I'm assuming you are familiar with the process. The app will not be very complicated and will consist of only one view/page.</p>
<h3 id="heading-prism-library">Prism Library</h3>
<p>I'm a fan of <a href="https://prismlibrary.com">Prism</a> for my Xamarin Forms apps, and will use it for this one, but the code will still work with standard Xamarin Forms or any other MVVM framework.
I'm using the <a href="https://marketplace.visualstudio.com/items?itemName=BrianLagunas.PrismTemplatePack">Prism Template Pack</a> to create as basic <strong>Xamarin.Forms Prism Blank App</strong>. This project template will stub out all the necessary files we need for this example.</p>
<h3 id="heading-xamarin-essentials">Xamarin Essentials</h3>
<p>First, add the <a href="https://www.nuget.org/packages/Xamarin.Essentials">Xamarin.Essentials NuGet Package</a> to your projects. If you're using MVVM (Like we're doing in this example), you'll ideally want to install the <a href="https://www.nuget.org/packages/Xamarin.Essentials.Interfaces">Xamarin.Essentials.Interfaces NuGet Package</a></p>
<h2 id="heading-android-project-changes">Android Project Changes</h2>
<p>In the Android project, add a new class called <strong>WebAuthenticationCallbackActivity</strong> and add the following code to it:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Android.App;
<span class="hljs-keyword">using</span> Android.Content.PM;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">XFCognito.Droid</span>
{
    [<span class="hljs-meta">Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop)</span>]
    [<span class="hljs-meta">IntentFilter(new[</span>] {Android.Content.Intent.ActionView},
        Categories = <span class="hljs-keyword">new</span>[] {Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable},
        DataScheme = <span class="hljs-string">"myxfcognitoapp"</span>)]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WebAuthenticationCallbackActivity</span>
        : <span class="hljs-title">Xamarin.Essentials.WebAuthenticatorCallbackActivity</span>
    {

    }
}
</code></pre>
<p>Make note of the DataScheme value, <strong>myxfcognitoapp</strong>, we are going to need this later.</p>
<p><strong>AndroidManifest.xml</strong>
If you're targeting Android 11, you'll need to add the following to AndroidManifest.xml:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">queries</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">intent</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">action</span> <span class="hljs-attr">android:name</span>=<span class="hljs-string">"android.support.customtabs.action.CustomTabsService"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">intent</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">queries</span>&gt;</span>
</code></pre>
<h2 id="heading-ios-project-changes">iOS Project Changes</h2>
<p><strong>Info.plist</strong>
In your iOS project add the following to Info.plist:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">key</span>&gt;</span>CFBundleURLTypes<span class="hljs-tag">&lt;/<span class="hljs-name">key</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">array</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">dict</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">key</span>&gt;</span>CFBundleURLName<span class="hljs-tag">&lt;/<span class="hljs-name">key</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">string</span>&gt;</span>myxfcognitoapp<span class="hljs-tag">&lt;/<span class="hljs-name">string</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">key</span>&gt;</span>CFBundleURLSchemes<span class="hljs-tag">&lt;/<span class="hljs-name">key</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">array</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">string</span>&gt;</span>myxfcognitoapp<span class="hljs-tag">&lt;/<span class="hljs-name">string</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">array</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">key</span>&gt;</span>CFBundleTypeRole<span class="hljs-tag">&lt;/<span class="hljs-name">key</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">string</span>&gt;</span>Editor<span class="hljs-tag">&lt;/<span class="hljs-name">string</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">dict</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">array</span>&gt;</span>
</code></pre>
<p>Note that we're using the same value(myxfcognitoapp), that we've used for the DataScheme value in Android for <strong>CFBundleURLName</strong> and <strong>CFBundleURLSchemes</strong>.</p>
<p><strong>AppDelegate.cs</strong>
Override the <strong>OpenUrl</strong> and <strong>ContinueUserActivity</strong> methods in the AppDelegate class with the following:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">OpenUrl</span>(<span class="hljs-params">UIApplication app, NSUrl url, NSDictionary options</span>)</span>
{
    <span class="hljs-keyword">if</span> (Xamarin.Essentials.Platform.OpenUrl(app, url, options))
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">base</span>.OpenUrl(app, url, options);
}

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">ContinueUserActivity</span>(<span class="hljs-params">UIApplication application, NSUserActivity userActivity, 
    UIApplicationRestorationHandler completionHandler</span>)</span>
{
    <span class="hljs-keyword">if</span> (Xamarin.Essentials.Platform.ContinueUserActivity(application, userActivity, completionHandler))
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">base</span>.ContinueUserActivity(application, userActivity, completionHandler);
}
</code></pre>
<blockquote>
<p><a href="https://docs.microsoft.com/en-us/xamarin/essentials/web-authenticator">The Xamarin.Essentials documentation</a> is an excellent resource if you need more information on how the Web Authenticator works. I can highly recommend it.</p>
</blockquote>
<h2 id="heading-shared-project-changes">Shared Project Changes</h2>
<p><strong>App.xaml.cs</strong>
Open the <strong>App.xaml.cs</strong> file and change the <strong>RegisterTypes</strong> method to the following:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">RegisterTypes</span>(<span class="hljs-params">IContainerRegistry containerRegistry</span>)</span>
{
    containerRegistry.RegisterSingleton&lt;IWebAuthenticator, WebAuthenticatorImplementation&gt;();

    containerRegistry.RegisterForNavigation&lt;NavigationPage&gt;();
    containerRegistry.RegisterForNavigation&lt;MainPage, MainPageViewModel&gt;();
}
</code></pre>
<p>All we're doing is registering the WebAuthenticator so that we can inject it into our ViewModel  and setting up the Prism navigation.</p>
<p><strong>MainPageViewModel.cs</strong>
Next, open the <strong>MainPageViewModel.cs</strong> class in the ViewModels folder. Change the code to the following:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Prism.Commands;
<span class="hljs-keyword">using</span> Prism.Navigation;
<span class="hljs-keyword">using</span> System;
<span class="hljs-keyword">using</span> System.Threading.Tasks;
<span class="hljs-keyword">using</span> Xamarin.Essentials.Interfaces;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">XFCognito.ViewModels</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">MainPageViewModel</span> : <span class="hljs-title">ViewModelBase</span>
    {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IWebAuthenticator _webAuthenticator;

        <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> _accessToken;
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> AccessToken
        {
            <span class="hljs-keyword">get</span> =&gt; _accessToken;
            <span class="hljs-keyword">set</span> =&gt; SetProperty(<span class="hljs-keyword">ref</span> _accessToken, <span class="hljs-keyword">value</span>);
        }

        <span class="hljs-keyword">private</span> DelegateCommand _loginCommand;
        <span class="hljs-keyword">public</span> DelegateCommand LoginCommand =&gt; _loginCommand ?? (_loginCommand = <span class="hljs-keyword">new</span> DelegateCommand(ExecuteLoginCommand));

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MainPageViewModel</span>(<span class="hljs-params">INavigationService navigationService, IWebAuthenticator webAuthenticator</span>) : <span class="hljs-title">base</span>(<span class="hljs-params">navigationService</span>)</span>
        {
            _webAuthenticator = webAuthenticator;
            Title = <span class="hljs-string">"AWS Cognito &amp; Xamarin Forms"</span>;
        }

        <span class="hljs-function"><span class="hljs-keyword">async</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ExecuteLoginCommand</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
                <span class="hljs-keyword">var</span> results = <span class="hljs-keyword">await</span> _webAuthenticator.AuthenticateAsync(
                    <span class="hljs-keyword">new</span> Uri(<span class="hljs-string">"https://myxamarinapp.auth.us-east-1.amazoncognito.com/login?client_id=4jlfe2iki0ucn32uc44clmib3d&amp;response_type=token&amp;scope=email+openid+profile&amp;redirect_uri=myxfcognitoapp://"</span>),
                    <span class="hljs-keyword">new</span> Uri(<span class="hljs-string">"myxfcognitoapp://"</span>));

                AccessToken = results?.AccessToken;
            }
            <span class="hljs-keyword">catch</span> (TaskCanceledException  e)
            {
                AccessToken = <span class="hljs-string">"You've cancelled."</span>;
            }
        }
    }

}
</code></pre>
<p>In the code above, we've created a property that will hold the <strong>AccessToken</strong> we get back from AWS Cognito, we've also added a <strong>LoginCommand</strong> that calls the Xamarin Essentials WebAuthenticator's <strong>AuthenticateAsync</strong> method.</p>
<p>The <strong>AuthenticateAsync</strong> method takes two parameters, the first is the URL to the AWS Hosted UI, you can get this by copying the URL that opens when clicking the <strong>Launch Hosted UI</strong> link in AWS Cognito's App client settings. 
The second parameter is the DataScheme value (myxfcognitoapp) that we've used previously with a colon and two forward slashes appended.</p>
<h2 id="heading-final-changes">Final Changes</h2>
<p>Go back to the App client settings in AWS Cognito and change the Callback URL(s) to the DataScheme value, in the following format:</p>
<p><strong>myxfcognitoapp://</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281659872/Rr0U7zpScY.png" alt="image" /></p>
<h2 id="heading-the-app-in-action">The app in action</h2>
<p>When running the app on Android, the first view will be the MainPage.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281661365/ijztNM9UF.png" alt="image" /></p>
<p>Tapping on the Login button, you'll be taken to the AWS Cognito Hosted Login page.
 <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281662899/T10Zife9d.png" alt="image" /></p>
<p>After entering your credentials and signing in, the app will navigate back to the MainPage and your <strong>AccesToken</strong> will be displayed.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281664426/axJJUH-jv.png" alt="image" /></p>
<p>This AccessToken can now be used to make any authenticated API calls you need.</p>
<p>The experience on iOS is similar: {% youtube F1rGnHGbb4I %}</p>
<p>Thank you for reading. Until next time, keep coding!</p>
<p>Full app source code is available on GitHub: <a href="https://github.com/Pietervdw/xamarinforms-awscognito">https://github.com/Pietervdw/xamarinforms-awscognito</a></p>
]]></content:encoded></item><item><title><![CDATA[How to publish a NuGet Package to GitHub Packages – The Quick Way]]></title><description><![CDATA[In the previous blog post, How to publish a NuGet Package to GitHub Packages, I’ve shown you hot to publish your NuGet package to GitHub Packages using the NuGet CLI.
Today, I’ll show you a way that is a little bit easier by using the Quick GitHub Pa...]]></description><link>https://mythicalmanmoth.com/how-to-publish-a-nuget-package-to-github-packages-the-quick-way</link><guid isPermaLink="true">https://mythicalmanmoth.com/how-to-publish-a-nuget-package-to-github-packages-the-quick-way</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Thu, 05 Nov 2020 08:16:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281146555/tb7tcz7Qm.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the previous blog post, How to publish a NuGet Package to GitHub Packages, I’ve shown you hot to publish your NuGet package to GitHub Packages using the NuGet CLI.</p>
<p>Today, I’ll show you a way that is a little bit easier by using the <a href="https://marketplace.visualstudio.com/items?itemName=CoalitionSoftware.quickgithubpackage">Quick GitHub Package</a> Visual Studio extension by <a href="https://coalition.software/">Coalition Software</a>.</p>
<h3 id="heading-download-the-extension">Download the extension</h3>
<p>Head over to the <a href="https://marketplace.visualstudio.com/items?itemName=CoalitionSoftware.quickgithubpackage">Visual Studio Marketplace</a> and click on the big green “<strong>Download</strong>” button. This will download a <strong>.vsix</strong> file. After the file has downloaded, double-click on it to install it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281166031/QPD1uB-2f.png" alt="image.png" /></p>
<h3 id="heading-your-project">Your Project</h3>
<p>First, you must make sure that your project is either configured to generate a NuGet Package when it builds:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281181838/WtonMnQsk.png" alt="image.png" /></p>
<p>You can also right-click on your project and select “Pack” from the context-menu:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281195190/kE-fxoGmd.png" alt="image.png" /></p>
<h3 id="heading-initial-setup">Initial Setup</h3>
<p>Next, right click on your project inside the Visual Studio Solution Explorer and click on “<strong>Create GitHub Package</strong>”</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281209847/NXm-esnoN.png" alt="image.png" /></p>
<h5 id="heading-setting-the-nuget-path">Setting the NuGet Path</h5>
<p>If it is the first time you run the extension, you will be prompted to select the path to the <strong>nuget.exe</strong> executable:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281223788/MxizPlPG_.png" alt="image.png" /></p>
<p>Choose the correct path to nuget.exe and click the “<strong>Use Selected Path</strong>” button to proceed to the next step.</p>
<h5 id="heading-adding-a-nuget-source">Adding a NuGet source</h5>
<p>Next, you’ll be prompted to create a new NuGet source, where the package must be pushed to:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281256300/xt43f4SGS.png" alt="image.png" /></p>
<p>The entries are explained below:</p>
<ul>
<li><strong>Name</strong> – Should be a friendly name for the package source</li>
<li><strong>Url</strong> –  Is the URL to your GitHub organizations’ NuGet package index.json</li>
<li><strong>GitHub Username</strong> – This should be the username of the GitHub account you’ve created to generate the personal access token above.</li>
<li><strong>GitHub Token</strong> – This is the personal access token that you created earlier.</li>
</ul>
<p>After you’ve completed all the necessary information, click on the “Add NuGet Source” button to proceed to the final step.</p>
<h5 id="heading-publish-your-nuget-package-to-github-packages">Publish your NuGet Package to GitHub Packages</h5>
<p>After you’ve completed the necessary setup steps. You’ll be able to push your NuGet Package to GitHub Packages. The extension will automatically pick up the path to the .nupkg file.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281270725/0NBRZJzkw.png" alt="image.png" /></p>
<p>All you need to do is to click the “<strong>Push GitHub Package</strong>” button and it will automatically push the package to your GitHub Packages. ‘</p>
<p>That is it, feel free to <a href="https://marketplace.visualstudio.com/items?itemName=CoalitionSoftware.quickgithubpackage">download</a> the extension and give it a test. Any problems, please let me know.</p>
<p>Thank you for reading. Until next time, keep coding!</p>
]]></content:encoded></item><item><title><![CDATA[How to publish a NuGet Package to GitHub Packages]]></title><description><![CDATA[Overview
At Coalition Software we have a number of in-house libraries for a variety of tasks such as sending email, managing multi-tenant applications and utilities for working with Cosmos Db.  Previously, to share these types of utility projects, yo...]]></description><link>https://mythicalmanmoth.com/how-to-publish-a-nuget-package-to-github-packages</link><guid isPermaLink="true">https://mythicalmanmoth.com/how-to-publish-a-nuget-package-to-github-packages</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Mon, 02 Nov 2020 08:15:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/W-ypTC6R7_k/upload/v1664281048440/dxwSyKZT3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-overview">Overview</h1>
<p>At Coalition Software we have a number of in-house libraries for a variety of tasks such as sending email, managing multi-tenant applications and utilities for working with Cosmos Db.  Previously, to share these types of utility projects, you had to either include the .DLL in the repository or reference it by adding the project to your Visual Studio solution. This worked, but it does add some administrative overhead.</p>
<p>With GitHub packages, we’re able to publish our in-house libraries as NuGet packages and easily use in our projects.</p>
<p>In this quick guide, I’ll show you how to publish your own libraries as NuGet Packages to GitHub Packages.</p>
<h1 id="heading-create-an-access-token">Create an Access Token</h1>
<p>Before you can push packages to GitHub you first need to create a Personal access token.</p>
<ul>
<li>Navigate to [https://github.com/](https://github.com/ "https://github.com/") and log in with your account.</li>
<li>Click on your profile image and select <strong>Settings  
</strong>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664280844370/Sa4YDp7_K.png" alt="image.png" /></li>
<li>On your Profile settings page, click on <strong>Developer settings</strong></li>
<li>Click on <strong>Personal access tokens</strong></li>
<li>Click the <strong>Generate new token</strong> button<strong>.</strong></li>
<li>Add a note about what the token is for and make sure to tick the <strong>read:packages</strong> scope.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664280863322/pP8_iycIH.png" alt="image.png" /></li>
</ul>
<p>With the token created, we can now add a new NuGet Source.</p>
<h1 id="heading-adding-a-new-nuget-source">Adding a new NuGet Source</h1>
<p>If you want to push NuGet packages to GitHub Packages, you must create a source using the NuGet CLI. To do this, you’ll need to execute the following command in your Command Prompt:</p>
<pre><code class="lang-console">nuget source Add -Name “[source-name]” -Source “https://nuget.pkg.github.com/[your-github-organization]/index.json” –UserName [your-github-username] –Password [your-github-access-token]
```console

Let’s take a closer look at the command parameters (marked in red) and what they mean:

*   **Name :** The Name parameter is what the source should be called, it can be anything. Ideally, you can give it a name like “Our GitHub Packages”
*   **Source :** The Source parameter should contain the url to your GitHub organizations’ NuGet package index.json. You can use the URL in the example and substitute your organization name.
*   **UserName :** This should be the username of the GitHub account you’ve created to generate the personal access token above.
*   **Password :** This is the personal access token that you created earlier.

If everything went according to plan, you should see a new Package source in Visual Studio. To check this, go to _Tools &gt; Options… &gt; NuGet Package Manager &gt; Package Sources  

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1664280927126/x1ypCunoJ.png align="left")

Set a NuGet ApiKey
==================

Although not necessary, it does make thing a bit smoother if we add an API Key for the newly added NuGet Source’s URL. To do this, execute the following command:

```console
nuget setApiKey [personal-access-token] -Source [https://nuget.pkg.github.com/[your-github-organization]/index.json](https://nuget.pkg.github.com/[your-github-organization]/index.json)
</code></pre>
<h1 id="heading-publish-to-github-packages">Publish to GitHub Packages</h1>
<p>To create a NuGet package for your project, you can use the <strong>nuget pack</strong> command or you can enable the “Generate NuGet package on build” option in your project properties.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664280966647/Okf3Bc6ez.png" alt="image.png" /></p>
<p>After the NuGet package has been generated. You can run the following command to push it to GitHub Packages:</p>
<pre><code class="lang-console">nuget push “E:Githubcoalition-softwareemailsrcbinReleaseCoalitionSoftware.Email.1.0.0.nupkg” -Source “Our Packages”
</code></pre>
<p>The first parameter should be the path to the .nupkg file that was generated by Visual Studio or the <strong>nuget pack</strong> command.</p>
<p>If everything worked, you should see your new package in GitHub:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281001628/RBrj1mhEP.png" alt="image.png" /></p>
<h1 id="heading-using-your-github-package-in-visual-studio">Using your GitHub Package in Visual Studio</h1>
<p>Finally, if we want to add our GitHub Package as a reference to a project in Visual Studio, we simply need to change the Package source dropdown to our newly added NuGet source:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664281018392/QaZSx8FUA.png" alt="image.png" /></p>
<p>Thank you for reading. Until next time, keep coding!</p>
]]></content:encoded></item><item><title><![CDATA[Xamarin Forms – Creating a Gradient Header]]></title><description><![CDATA[In the design document for the Doctriod app you would’ve noticed that it uses a gradient header. To achieve a similar effect (shown in the screenshots below) in Xamarin Forms, we need to make changes in the Shared, Android and iOS project.


Shared P...]]></description><link>https://mythicalmanmoth.com/xamarin-forms-creating-a-gradient-header</link><guid isPermaLink="true">https://mythicalmanmoth.com/xamarin-forms-creating-a-gradient-header</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Mon, 22 Apr 2019 09:21:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/eICUFSeirc0/upload/v1664280666822/-SM-Lw-CR.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the design document for the Doctriod app you would’ve noticed that it uses a gradient header. To achieve a similar effect (shown in the screenshots below) in Xamarin Forms, we need to make changes in the Shared, Android and iOS project.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664280613877/D2_87f1rl.png" alt="image.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664280629664/W1SqiHBYd.png" alt="image.png" /></p>
<h3 id="heading-shared-project">Shared Project</h3>
<p>Start by creating a custom <strong>NavigationPage</strong> class in the shared project (<em>Doctriod</em>) called <code>GradientHeaderNavigationPage</code>. The class should inherit from the <code>NavigationPage</code> class.</p>
<p>The only thing happening in the class mentioned above is that we’re setting the navigation bar text color to white. Next, because the project uses <a href="https://prismlibrary.github.io/">Prism</a>, we need to change the<br /><code>RegisterTypes</code> method in the <code>App</code> class (<em>App.xaml.cs</em>) to use our newly created <code>GradientHeaderNavigationPage</code> class instead of the normal <code>Navigationpage</code>.</p>
<h3 id="heading-android-project">Android Project</h3>
<p>In your Android project(<em>Doctriod.Android</em>) create a new class called <code>GradientHeaderNavigationPageRenderer</code> in the <em>Renderers</em> folder. The class inherits from <code>NavigationPageRenderer</code> and there’s a lot of stuff happening this class, but the method that does the work is called <code>SetGradientBackground</code> which in turn is called from <code>OnViewAdded</code></p>
<p>You can view the <em>GradientHeaderNavigationPageRenderer.cs</em> file in its entirety on <a href="https://github.com/Pietervdw/doctriod-xamarin/blob/master/src/Doctriod/Doctriod/Doctriod.Android/Renderers/GradientHeaderNavigationPageRenderer.cs">Github</a></p>
<h3 id="heading-ios-project">iOS Project</h3>
<p>Our last step will be to create a new class called <code>GradientHeaderPageRenderer</code> in our iOS project(<em>Doctriod.iOS</em>) You can create the file anywhere inside the iOS project, but I like to create renderers inside the <em>Renderers</em> folder.</p>
<p>The <code>GradientHeaderPageRenderer</code> will inherit from <code>PageRenderer</code> and the method that does most of the work is called <code>SetGradientBackground</code> and is called from <code>ViewWillAppear</code></p>
<p>You can view the contents of the entire file on <a href="https://github.com/Pietervdw/doctriod-xamarin/blob/master/src/Doctriod/Doctriod/Doctriod.iOS/Renderers/GradientHeaderPageRenderer.cs">Github</a>.</p>
<p>That should do it. If all goes well you should see similar results as shown in the images at the top of this post. Additional reading and research I used to compile this post is listed below.</p>
<p>Thank you for reading. Until next time, keep coding!</p>
<h3 id="heading-additional-reading">Additional Reading</h3>
<ul>
<li>[https://github.com/CrossGeeks/CustomNavigationBarSample](https://github.com/CrossGeeks/CustomNavigationBarSample "https://github.com/CrossGeeks/CustomNavigationBarSample")</li>
<li>[https://stackoverflow.com/questions/46809733/how-to-add-a-gradient-in-xamarin-forms-toolbar-and-uinavigationbar](https://stackoverflow.com/questions/46809733/how-to-add-a-gradient-in-xamarin-forms-toolbar-and-uinavigationbar "https://stackoverflow.com/questions/46809733/how-to-add-a-gradient-in-xamarin-forms-toolbar-and-uinavigationbar")</li>
<li>[https://forums.xamarin.com/discussion/132362/cross-platform-gradient-navigationbar](https://forums.xamarin.com/discussion/132362/cross-platform-gradient-navigationbar "https://forums.xamarin.com/discussion/132362/cross-platform-gradient-navigationbar")</li>
<li>[https://github.com/vackup/StatusBarGradientBackground/](https://github.com/vackup/StatusBarGradientBackground/ "https://github.com/vackup/StatusBarGradientBackground/")</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Xamarin Forms–Creating a Gradient Drawer Menu]]></title><description><![CDATA[After more than a year of hiatus of writing blog posts, I’m back. This post is the first in a series that was originally intended to form part of a book called “From Design to App Store – Building a Xamarin Forms app using Adobe XD and Prism”.
Pretty...]]></description><link>https://mythicalmanmoth.com/xamarin-formscreating-a-gradient-drawer-menu</link><guid isPermaLink="true">https://mythicalmanmoth.com/xamarin-formscreating-a-gradient-drawer-menu</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Sun, 31 Mar 2019 08:27:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/LeG68PrXA6Y/upload/v1664280549145/24gCBsSNY.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After more than a year of hiatus of writing blog posts, I’m back. This post is the first in a series that was originally intended to form part of a book called “From Design to App Store – Building a Xamarin Forms app using Adobe XD and Prism”.</p>
<p>Pretty catchy title right?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664280467507/gnxw0raB0.png" alt="image.png" /></p>
<p>The book would have detailed the steps involved in taking an app design in Adobe XD and creating a Xamarin Forms app from it. The app would’ve used <a href="https://prismlibrary.github.io/">Prism</a> as its MVVM framework and the design it was going to use was called <a href="https://www.behance.net/gallery/58242781/Doctriod-Health-Care-App-UI-Kit-For-Free">Doctriod</a> by Jitu Raut. The design is fantastic and I urge you to use it for your apps. It does have a few challenging design aspects which was one of the reasons I chose it.</p>
<p>I have however decided to rather post the content of the book as a series of blog posts. There are not a lot of Xamarin Forms posts on achieving certain designs and I thought you might benefit more from a few blogs posts than from a book.</p>
<p>So without further ado, let’s get cracking…</p>
<h3 id="heading-creating-a-gradient-drawer-menu">Creating a Gradient Drawer Menu</h3>
<p>The effect we’re trying to achieve is represented in the following images for Android and iOS:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664280490791/uCiUF1dlw.png" alt="image.png" /></p>
<h4 id="heading-shared-project">Shared Project</h4>
<p>The first step you need to take is to create a new class called <code>GradientContentPage</code> that inherits from <code>ContentPage</code> in your shared project (Mine is called <em>Doctriod</em>). There is not much happening in this class other than two properties:</p>
<p>Next, open the Master-Detail Page and add the <code>GradientContentPage</code> as a child element of <code>&lt;MasterDetailPage.Master&gt;</code></p>
<h4 id="heading-android-project">Android Project</h4>
<p>In your Android project (in my case its called <em>Doctriod.Android</em>) add a new file called <code>GradientContentPageRenderer</code>. I like to put any custom renderers into a folder called <em>Renderers</em> The file content should look like the following:</p>
<h4 id="heading-ios-project">iOS Project</h4>
<p>The last step is to make this work for iOS, add a new file called <code>GradientContentPageRenderer</code> to your iOS project (Mine is called Doctriod.iOS). Similar to the Android project, it is located in the <em>Renderers</em> folder.</p>
<p>That should just about do it. If you want to see the complete solution, I’ve open-sourced the project for the book and you can find it on <a href="https://github.com/Pietervdw/doctriod-xamarin">Github</a></p>
]]></content:encoded></item><item><title><![CDATA[Creating a movie app using Xamarin.Forms and Prism – Part 2]]></title><description><![CDATA[In the previous post, Creating a movie app using Xamarin.Forms and Prism – Part 1, we went through the process of creating and setting up a new Xamarin. Forms project using the Prism library and Visual Studio.
In today’s post, we’ll go through the st...]]></description><link>https://mythicalmanmoth.com/creating-a-movie-app-using-xamarinforms-and-prism-part-2</link><guid isPermaLink="true">https://mythicalmanmoth.com/creating-a-movie-app-using-xamarinforms-and-prism-part-2</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Tue, 23 Jan 2018 11:42:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/J39X2xX_8CQ/upload/v1664280262852/6djWesRKr.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the previous post, Creating a movie app using Xamarin.Forms and Prism – Part 1, we went through the process of creating and setting up a new Xamarin. Forms project using the Prism library and Visual Studio.</p>
<p>In today’s post, we’ll go through the steps of retrieving data from the web service and displaying it in a list view.</p>
<p>Since Part 1, the Prism library has had significant updates. If you’ve created the app from scratch before the Prism updates, you would need to update your NuGet packages as well as the <code>RegisterTypes</code> method in the <code>App.xaml.cs</code>, <code>MainActivity.cs</code> and <code>AppDelegate.cs</code> file in each project, to the following:</p>
<h3 id="heading-file-open-project">File, Open Project</h3>
<p>We’ll continue on the code we created Part 1. You can get all the code for this series on <a href="https://github.com/Pietervdw/my-moviedb">GitHub</a>, so go ahead and open the project you created in Part 1. We’re going to show a list of movie genres on the first page of the app. The project already contains a <code>MainPageViewModel</code> class which we can use, however, we’ll add our own Genre page and ViewModel by following these steps:</p>
<ol>
<li>Right-click on the <strong>Views</strong> folder inside the Solution Explorer and select <strong>Add &gt; New Item  
</strong></li>
<li>Select Prism &gt; Prism ContentPage (Xamarin.Forms), name the file <code>GenrePage.xaml</code> and click the <strong>Add</strong> button.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664280305933/uqFz4JHCV.png" alt="image.png" /></p>
<p>Because you’re using the Prism ContentPage item template, it will automatically create the following files for you:</p>
<ul>
<li>A <code>GenrePage.xaml</code> file with it’s associated code-behind <code>Genre.xaml.cs</code> and;</li>
<li>A <code>GenrePageViewModels.cs</code> file inside the <strong>ViewModels</strong> folder, which will act as the new page’s associated view model.</li>
</ul>
<p>It will also automatically register the newly created page for navigation by adding the following line to the<br /><code>RegisterTypes</code> method in the <code>App.xaml.cs</code> file:</p>
<pre><code> containerRegistry.RegisterForNavigation();
</code></pre><p>Now, since we want to display a list of movie genres when the app first opens, we need to specify that the newly added GenrePage, should be the first page that is shown. To do this open <code>App.xaml.cs</code> and change the following line:</p>
<pre><code class="lang-csharp">         <span class="hljs-keyword">await</span> NavigationService.NavigateAsync(<span class="hljs-string">"NavigationPage/MainPage"</span>);
</code></pre>
<p>to</p>
<pre><code class="lang-csharp">         <span class="hljs-keyword">await</span> NavigationService.NavigateAsync(<span class="hljs-string">"NavigationPage/GenrePage"</span>);
</code></pre>
<h3 id="heading-loading-data">Loading Data</h3>
<p>Next, we need to fetch a list of movie genres from The Movie DB API and populate a list view on the Genre page. First, we need to make a small change to the ViewModelBase class by doing the following:</p>
<ol>
<li>Open the <code>ViewModelBase.cs</code> file in the <strong>ViewModels</strong> folder.</li>
<li>Add a new property called <code>IsBusy</code> to the <code>ViewModelBase</code> class. You can use the Prism <em>propp</em> snippet to make this easier. The property should look like:</li>
</ol>
<p>If you want to learn more about the available Prism snippets, be sure to read my post, <a href="https://mythicalmanmoth.com/2018/01/11/prism-library-quick-tip-snippets/">Prism Library Quick Tip – Snippets</a></p>
<p>Next, we need to work on the view model for the Genre page.</p>
<ol>
<li>Open the <code>GenrePageViewModel.cs</code> file inside the <strong>ViewModels</strong> folder.</li>
<li>Change the class to inherit from <code>ViewModelBase</code> and add a constructor with two parameters, one of type <code>INavigationService</code> and another <code>IMovieRepository</code>:</li>
<li>Add an <code>ObservableCollection</code> property, called <strong>Genres</strong>, that will contain a list of genres to the class:</li>
<li>Next, add a new <code>DelegateCommand</code>, which will be used to retrieve the genre data, called <strong>LoadGenresCommand</strong>. Use the <em>cmd</em> snippet to generate most of the code for you.</li>
<li>Change the <code>LoadGenres()</code> method to the following (The <code>ToObservableCollection</code> method is an extension method in the <code>ListExtensions</code> class inside the <strong>Extensions</strong> folder):</li>
<li>Next, add the following line to the class constructor in order to execute the LoadGenres command:</li>
</ol>
<pre><code class="lang-csharp">     LoadGenresCommand.Execute();
</code></pre>
<ol>
<li>Lastly, to register the required dependencies, add the following to the <code>RegisterTypes</code> method in the <code>App.xaml.cs</code> class:</li>
</ol>
<h3 id="heading-creating-the-ui">Creating the UI</h3>
<p>At this point, we have all the necessary code in place, we just need to create the UI to list the genres. We’ll create a simple UI to start with, that will only list the available movie genres, by completing the following steps:</p>
<ol>
<li>Open the <code>GenrePage.xaml</code> file inside the View folder</li>
<li>Replace the content of the <code>GenrePage.xaml</code> with the following:</li>
</ol>
<p>In the code above, we bind the page title to the view model’s <strong>Title</strong> property, as well as bind the list view to the <strong>Genres</strong> property. Note, that we also bind <strong>IsRefreshing</strong> to our view models’ <strong>IsBusy</strong> property – this will automatically show a progress indicator when the data loads.</p>
<p>You should now be able to see a list of genres retrieved from The Movie Db:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664174698824/DfnLaZrBr.gif" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664174701143/Vt8I-WEex.gif" alt /></p>
<p>If you’re having problems running the example on iOS, do not panic. There are a few things we need to do to make it work that will be covered in Part 3.</p>
<p>In the next part, we’ll create another page showing all movies for a specific genre and the movie detail. You can find all code for this series on <a href="https://github.com/Pietervdw/my-moviedb">GitHub.</a></p>
<p>Thank you for reading. Until next time, keep coding!</p>
]]></content:encoded></item><item><title><![CDATA[Prism Library Quick Tip – Snippets]]></title><description><![CDATA[The Prism Template pack, available on Visual Studio Marketplace, offers a collection of helpful snippets to speed up your development. To use the snippets in Visual Studio, simply type the shortcut (e.g. propp) and press TAB.
Here is a quick list of ...]]></description><link>https://mythicalmanmoth.com/prism-library-quick-tip-snippets</link><guid isPermaLink="true">https://mythicalmanmoth.com/prism-library-quick-tip-snippets</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Thu, 11 Jan 2018 11:44:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664280106672/uryiblPLF.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The Prism Template pack, available on <a href="https://marketplace.visualstudio.com/items?itemName=BrianLagunas.PrismTemplatePack">Visual Studio Marketplace</a>, offers a collection of helpful snippets to speed up your development. To use the snippets in Visual Studio, simply type the shortcut (e.g. propp) and press TAB.</p>
<p>Here is a quick list of each as a handy reference:</p>
<h3 id="heading-propp">propp</h3>
<p>Generate a property with a backing field, that depends on <code>BindableBase</code>. This means it will generate a standard property, but with a setter that uses the <code>BindableBase</code> <code>SetProperty</code> method, e.g.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> fieldName;
<span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> PropertyName
{
    <span class="hljs-keyword">get</span> { <span class="hljs-keyword">return</span> fieldName; }
    <span class="hljs-keyword">set</span> { SetProperty(<span class="hljs-keyword">ref</span> fieldName, <span class="hljs-keyword">value</span>); }
}
</code></pre>
<h3 id="heading-cmd">cmd</h3>
<p>Generates a <code>DelegateCommand</code> property, with backing field and the associated Execute method, e.g.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">private</span> DelegateCommand _fieldName;
<span class="hljs-keyword">public</span> DelegateCommand CommandName =&gt;
    _fieldName ?? (_fieldName = <span class="hljs-keyword">new</span> DelegateCommand(ExecuteCommandName));

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">ExecuteCommandName</span>(<span class="hljs-params"></span>)</span>
{

}
</code></pre>
<h3 id="heading-cmdfull">cmdfull</h3>
<p>Generate a <code>DelegateCommand</code> property, with backing field as well as its associated Execute method. It also creates the CanExecute method for you, e.g.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">private</span> DelegateCommand _fieldName;
<span class="hljs-keyword">public</span> DelegateCommand CommandName =&gt;
    _fieldName ?? (_fieldName = <span class="hljs-keyword">new</span> DelegateCommand(ExecuteCommandName, CanExecuteCommandName));

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">ExecuteCommandName</span>(<span class="hljs-params"></span>)</span>
{

}

<span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">CanExecuteCommandName</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
</code></pre>
<h3 id="heading-cmdg">cmdg</h3>
<p>Similar to the <strong>cmd</strong> snippet mentioned above, but this one generates a generic <code>DelegateCommand</code> property</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">private</span> DelegateCommand&lt;<span class="hljs-keyword">string</span>&gt; _fieldName;
<span class="hljs-keyword">public</span> DelegateCommand&lt;<span class="hljs-keyword">string</span>&gt; CommandName =&gt;
    _fieldName ?? (_fieldName = <span class="hljs-keyword">new</span> DelegateCommand&lt;<span class="hljs-keyword">string</span>&gt;(ExecuteCommandName));

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">ExecuteCommandName</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> parameter</span>)</span>
{

}
</code></pre>
<h3 id="heading-cmdgfull">cmdgfull</h3>
<p>Similar to the <strong>cmdfull</strong> snippet mentioned above, but this one generates a generic <code>DelegateCommand</code> property with its associated Execute and CanExecute Methods</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">private</span> DelegateCommand&lt;<span class="hljs-keyword">string</span>&gt; _fieldName;
<span class="hljs-keyword">public</span> DelegateCommand&lt;<span class="hljs-keyword">string</span>&gt; CommandName =&gt;
    _fieldName ?? (_fieldName = <span class="hljs-keyword">new</span> DelegateCommand&lt;<span class="hljs-keyword">string</span>&gt;(ExecuteCommandName, CanExecuteCommandName));

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">ExecuteCommandName</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> parameter</span>)</span>
{

}

<span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">CanExecuteCommandName</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> parameter</span>)</span>
{
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
</code></pre>
<p>These snippets are incredibly  handy when working with Prism as it really makes it easy to add the code elements essential for the framework to work smoothly.</p>
<p>To read more about the Prism Library, visit [http://prismlibrary.com/](http://prismlibrary.com/ "http://prismlibrary.com/")</p>
<p>Thank you for reading. Until next time, keep coding!</p>
]]></content:encoded></item><item><title><![CDATA[Creating a movie app using Xamarin.Forms and Prism – Part 1]]></title><description><![CDATA[Today, we’ll start with setting up a new project using Xamarin.Forms and the Prism Library. Our app will be a simple movie database that lists and displays information about movies.We’ll  be using the The Movie Db API, which is a free service. Read m...]]></description><link>https://mythicalmanmoth.com/creating-a-movie-app-using-xamarinforms-and-prism-part-1</link><guid isPermaLink="true">https://mythicalmanmoth.com/creating-a-movie-app-using-xamarinforms-and-prism-part-1</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Thu, 04 Jan 2018 11:54:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/MAYsdoYpGuk/upload/v1664279874738/avbJpFTaV.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today, we’ll start with setting up a new project using Xamarin.Forms and the Prism Library. Our app will be a simple movie database that lists and displays information about movies.<br />We’ll  be using the The Movie Db API, which is a free service. Read more at [https://www.themoviedb.org/documentation/api](https://www.themoviedb.org/documentation/api "https://www.themoviedb.org/documentation/api")</p>
<p>I wont be delving too deep into Xamarin.Forms and Prism, instead I’ll rather focus on showing you how to use the tools at your disposal. Needless to say, if you want to learn more about Xamarin, head over to <a href="http://university.xamarin.com/">Xamarin University</a>, they have excellent content and the instructors know their stuff. If you need more information about Prism, it is all open source and the documentation helps you get started quickly. Check it out at [http://prismlibrary.github.io/](http://prismlibrary.github.io/ "http://prismlibrary.github.io/")</p>
<p>Without further ado, lets get started!</p>
<h3 id="heading-file-new-project">File, New, Project</h3>
<p>Our first step is to create a new project in Visual Studio. Fire up Visual Studio 2017 and select <strong>File&gt; New &gt; Project</strong>. In the New Project dialog window, select <strong>Prism Blank App (Xamarin.Forms)</strong>. You’ll find the the project template under <strong>Visual C# &gt; Prism</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664279893993/ehVF6VYrd.png" alt="image.png" /></p>
<p>Not seeing the template in Visual Studio? You need to install the<br /><a href="https://marketplace.visualstudio.com/items?itemName=BrianLagunas.PrismTemplatePack">Prism Template Pack</a>.</p>
<p>Click <strong>OK</strong> and select the platform your app will support, Android and iOS for this example. You can also select your preferred DI container. I’ve read some good things about <strong>Dryloc</strong>, so for this example we’ll use it.<br />Next, click <strong>Create Project</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664279912016/H2U69-CpO.png" alt="image.png" /></p>
<p>Which container should I use? Honestly, it is down to personal preference. Prism provides an abstraction over the container, which means it isn’t tied to any specific implementation. You’ll see what I mean as we continue with the project.<br />You can read more about in the <a href="https://prismlibrary.readthedocs.io/en/latest/WPF/03-Managing-Dependencies/">Prism docs</a>.</p>
<p>The project wizard will generate the initial project layout for you. When finished, you should see a solution structure similar to the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664279930531/GDRHVO80d.png" alt="image.png" /></p>
<h3 id="heading-shared-project-structure">Shared Project structure</h3>
<p>We’ll focus mostly on the shared project (<strong>MyMovieDb</strong>) in this post. I prefer to follow the layout as detailed in Gill Cleeren’s <a href="https://www.pluralsight.com/courses/mvvm-based-architecture-xamarin-mobile-apps">Building an MVVM-based Architecture for Xamarin Mobile Apps Pluralsight</a> course, which I can recommend that you watch.</p>
<p>First, let’s go ahead and add a few folders to help structure our code:</p>
<ol>
<li>Add a new folder called <strong>Contracts</strong></li>
<li>Add two subfolders to the <strong>Contracts</strong> folder called <strong>Repositories</strong> and <strong>Services.</strong> These two folders will contain the Interface declarations for our repository and services classes.</li>
<li>Create another two folders in the root of the <strong>MyMovieDb</strong> project, called <strong>Repositories</strong> and <strong>Services.</strong> The folders will contain the implementations of the repository and services classes.</li>
<li>And another called <strong>Models.</strong> This folder will contain any model classes.</li>
<li>Almost done. Add another folder for any custom value converters called <strong>Converters</strong>.</li>
<li>Lastly, add a folder called <strong>Extensions</strong>, which will contain any extension method classes.</li>
</ol>
<p>The final layout of our shared project, should resemble something like the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664279950728/Z4vE1Y0ra.png" alt="image.png" /></p>
<h3 id="heading-installing-required-nuget-packages">Installing required NuGet packages</h3>
<h5 id="heading-tmdblib">TMDbLib</h5>
<p>We’ll need a way to retrieve data from <a href="https://www.themoviedb.org/documentation/api">The Movie DB API</a>.  Luckily, a .Net wrapper library, for said API, has already been written and is available as a NuGet package. To install it, right-click on the shared code project (<strong>MyMovieDb</strong>) and select <strong>Manage  Nuget Packages…</strong> from the context-menu.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664279966325/9vSs7KXfT.png" alt="image.png" /></p>
<p>Click on <strong>Browse</strong> and enter <strong>TMDbLib</strong> in the Search box. You should see the TMDbLib by LordMike in the list of available packages. Click on the <strong>Install</strong> button on the right to install the library into your shared project.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664279981595/MMWcimKCD.png" alt="image.png" /></p>
<p>With the wrapper library installed, we can get to work adding classes to make retrieving data easier.</p>
<h5 id="heading-automapper">AutoMapper</h5>
<p>Next, we’ll need AutoMapper to take care of some of the heavy lifting in mapping objects. To install it, follow the steps detailed above, but this time search for the AutoMapper library:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664279996634/Ui6w0eXJp.png" alt="image.png" /></p>
<h3 id="heading-to-the-code">To the code!</h3>
<p>With the necessary references in place, let’s get down to writing some code!</p>
<ol>
<li><p>Right click on the <strong>Models</strong> folder, and add a new class called <code>Genre</code>.  </p>
</li>
<li><p>Right click on the <strong>Services</strong> subfolder in the <strong>Contracts</strong> folder, and add a new interface called <code>IMovieService</code>.  </p>
</li>
<li><p>Next, right-click on the <strong>Repositories</strong> subfolder in the <strong>Contracts</strong> folder, and create a new interface called <code>IMovieRepository</code>.      </p>
</li>
</ol>
<p>After we’ve created the interfaces, we can now start writing the implementation for each.</p>
<ol>
<li><ol>
<li><ol>
<li>Add a new class, called <code>MovieRepository</code> to the <strong>Repositories</strong> folder and make sure that it implements the<br /><code>IMovieRepository</code> interface.</li>
<li>Add a using to the TMDbLib library to your class: <code>using TMDbLib.Client;</code></li>
<li>Add a new local TMDbClient variable called <code>_client</code> to the <code>MovieRepository</code> class. Be sure to pass in your The Movie DB API Key as part<br />of it’s constructor arguments :<br /><code>TMDbClient _client = new TMDbClient("---YOUR-API-KEY---");</code></li>
<li>Add the following code to the <code>GetGenres()</code> method:  </li>
</ol>
</li>
</ol>
</li>
</ol>
<p>The full code listing for the <code>MovieRepository</code> class should look similar to the following:</p>
<ol>
<li>Next, in the <strong>Services</strong> folder. Add a new class called <code>MovieService</code>.</li>
<li>The <code>MovieService</code> class should implement the <code>IMovieService</code> interface</li>
<li>Add a constructor for the <code>MovieService</code> class, that accept an <code>IMovieService</code> parameter</li>
<li>Add a local variable of type <code>IMovieService</code> called, <code>_movieRepo</code> to the class</li>
<li>Set the <code>_movieRepo</code> variable equal to the constructor parameter</li>
<li>Finally, call the <code>_movieRepo.GetGenres()</code> method from the <code>GetGenres()</code> method of the <code>MovieService</code> class.</li>
</ol>
<p>The full code listing for the <code>MovieService</code> class follows:</p>
<h3 id="heading-last-steps">Last steps</h3>
<p>You might’ve notice we use a <code>Mapper</code> object to map the TmDbLib <code>Genre</code> object to our own <code>Genre</code> object (in the <strong>Models</strong> folder). This is done using the AutoMapper libary, and in order to make this work, we first need to perform the following steps:</p>
<ol>
<li>Open the <strong>App.xaml</strong> file’s code-behind, <strong>App.xaml.cs</strong></li>
<li><p>Add a new private method called <code>InitAutoMapper()</code> to the class. This method will create the mapping for the objects we need:  </p>
</li>
<li><p>Next, call the <code>InitAutoMapper()</code> method inside the <code>OnInitialized()</code> method : <code>InitAutoMapper();</code></p>
</li>
</ol>
<p>And with that, we’re at the end of this post. In the next post, we’ll get down to business and start invoking the web service calls and display the data on the UI.</p>
<p>Thank you for reading! This one is for you Rodg.</p>
<h3 id="heading-links-for-this-post">Links for this post:</h3>
<ul>
<li><a href="https://github.com/Pietervdw/my-moviedb">GitHub repo for this blog series</a></li>
<li><a href="http://prismlibrary.github.io/">Prism Library</a></li>
<li><a href="https://developers.themoviedb.org/3/getting-started/introduction">The Movie Db API Developer Docs</a></li>
<li><a href="https://github.com/LordMike/TMDbLib/">TMDBLib on GitHub</a></li>
<li><a href="http://automapper.org/">AutoMapper</a></li>
</ul>
<p><strong>Before you go,</strong> the code presented in this blog post is just one approach of many. If you see a mistake or know of a better way to accomplish the tasks detailed here, please feel free to share it, in the comments section below, in a respectful and clear way. Any comments and suggestions are always appreciated.</p>
]]></content:encoded></item><item><title><![CDATA[ReSharper Tip – Creating a “Surround With” template]]></title><description><![CDATA[I’m not going to deny it. I’m a fan of ReSharper. One of it’s many feature is the ability to create your own code templates.
Whilst busy with a Xamarin Forms project. I needed a quick way to surround blocks of XAML code with a region.
Yes, you can ad...]]></description><link>https://mythicalmanmoth.com/resharper-tip-creating-a-surround-with-template</link><guid isPermaLink="true">https://mythicalmanmoth.com/resharper-tip-creating-a-surround-with-template</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Wed, 20 Dec 2017 12:24:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/pdRsf77OBoo/upload/v1664279785203/zqpweZbOB.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I’m not going to deny it. I’m a fan of ReSharper. One of it’s many feature is the ability to create your own code templates.</p>
<p>Whilst busy with a Xamarin Forms project. I needed a quick way to surround blocks of XAML code with a region.</p>
<p>Yes, you can add regions to XAML code. To give you an idea of what I mean, here is a small example of a region in XAML:</p>
<p>So, let’s quickly go through the steps of creating a ReSharper template to surround any piece of XAML code with the correct markup for a region.</p>
<ol>
<li>In Visual Studio, select ReSharper &gt; Tools &gt; Templates Explorer…</li>
<li>Click on the <strong>Surround Templates</strong> Tab.</li>
<li>Click the <strong>New Template</strong> toolbar button.</li>
<li><p>Add the following code to the template editor window:  </p>
</li>
<li><p>Set the following properties for the template:</p>
</li>
<li><p><strong>Shortcut</strong>: region</p>
</li>
<li><strong>Description</strong>: Surrounds XAML with a region</li>
<li><p><strong>Mnemonic</strong>: 2</p>
</li>
<li><p>Make sure the <strong>Reformat</strong> and <strong>Surrounding</strong> checkbox and radio button is selected.</p>
</li>
<li>Click on the “link” text next to availability and check the “<strong>In File matching: *.*</strong>” checkbox.</li>
<li>Set the <strong>File Mask</strong> to *.xaml</li>
<li>Lastly, check the “<strong>Show in context action</strong>” checkbox and save the template.</li>
</ol>
<p>The final result should look like the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664279719170/n69fFSysS.png" alt="image.png" /></p>
<p>Now, when you select a piece of XAML code, you should see region inside the ReSharper “Surround with” context menu:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664279736261/ipzdNeXDs.png" alt="image.png" /></p>
<p>The result will be the code nicely wrapped inside a region, which can be collapsed to help with readability:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664279757119/q7uZUoyoo.png" alt="image.png" /></p>
<p>Thank you for reading. Until next time, keep coding!</p>
]]></content:encoded></item><item><title><![CDATA[Introducing the .NET wrapper for the Sage One Accounting API]]></title><description><![CDATA[A while back my accountant convinced me to move our accounting package to Sage One Online. Not only am I very happy with the change, I’m also intrigued with their API, which enables developers to integrate with Sage One and perform a wide range of ta...]]></description><link>https://mythicalmanmoth.com/introducing-the-net-wrapper-for-the-sage-one-accounting-api</link><guid isPermaLink="true">https://mythicalmanmoth.com/introducing-the-net-wrapper-for-the-sage-one-accounting-api</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Tue, 08 Sep 2015 13:04:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/fPyE0Xl-C2g/upload/v1664279659297/Q0iusH6bS.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A while back my accountant convinced me to move our accounting package to Sage One Online. Not only am I very happy with the change, I’m also intrigued with their API, which enables developers to integrate with Sage One and perform a wide range of tasks . As a result I’ve created an open source project with the aim to create a fully fledged .Net wrapper library for the Sage One Accounting API. The code is available on <a href="https://github.com/Pietervdw/sageone-api-wrapper"><strong>GitHub</strong></a>, so please feel free to grab your fork and start contributing! The project is still under active development and I’m adding features as I need them. As of writing, the library supports the following operation s:  </p>
<ul>
<li><p><strong>Account</strong></p>
<ul>
<li>Get All</li>
<li>Get</li>
<li>Save (Create and Update)</li>
<li>Delete</li>
<li>Get with System Accounts</li>
<li>Get by Category</li>
</ul>
</li>
<li><p><strong>Customer</strong></p>
<ul>
<li>Get All</li>
<li>Get</li>
<li>Save (Create and Update)</li>
<li>Delete</li>
</ul>
</li>
<li><p><strong>Company</strong></p>
<ul>
<li>Get Current</li>
</ul>
</li>
<li><p><strong>Item</strong></p>
<ul>
<li>Get All</li>
<li>Get</li>
<li>Save (Create and Update)</li>
<li>Delete</li>
</ul>
</li>
<li><p><strong>Categories (Account, Asset, Bank Account, Customer, Item, Supplier)</strong></p>
<ul>
<li>Get All</li>
<li>Get</li>
<li>Save (Create and Update) excl. Account Categories</li>
<li>Delete</li>
</ul>
</li>
<li><p><strong>Sales Representative</strong></p>
<ul>
<li>Get All</li>
<li>Get</li>
<li>Save (Create and Update)</li>
<li>Delete</li>
<li>HasActivity</li>
</ul>
</li>
<li><p><strong>Supplier</strong></p>
<ul>
<li>Get All</li>
<li>Get</li>
<li>Save (Create and Update)</li>
<li>Delete</li>
</ul>
</li>
<li><p><strong>Tax Invoice</strong></p>
<ul>
<li>Get All</li>
<li>Get</li>
<li>Save (Create and Update)</li>
<li>Calculate</li>
</ul>
</li>
</ul>
<p>For example to get a list of customers on Sage One you’ll use the following C# code:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">GetAllCustomers</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> api = <span class="hljs-keyword">new</span> ApiRequest(Username, Password, Apikey, CompanyId);
    <span class="hljs-keyword">var</span> customers = api.CustomerRequest.Get();
}
</code></pre>
<p>The Sage One API is pretty neat in the fact that it support OData queries out of the box. For example to find a customer with an e-mail address, you can simply pass in a filter parameter to the Get method:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">GetCustomerByEmail</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">string</span> filter = <span class="hljs-string">"Email eq 'info@contoso.com'"</span>;
    <span class="hljs-keyword">var</span> api = <span class="hljs-keyword">new</span> ApiRequest(Username, Password, Apikey, CompanyId);
    <span class="hljs-keyword">var</span> customers = api.CustomerRequest.Get(filter);
}
</code></pre>
<p>In case you’re wondering how OData queries work, take a look at the following <a href="http://www.odata.org/documentation/odata-version-2-0/uri-conventions/">example</a>. The load a customer by ID, you’ll use the following:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">GetCustomer</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">int</span> customerId = <span class="hljs-number">12345</span>;
    <span class="hljs-keyword">var</span> api = <span class="hljs-keyword">new</span> ApiRequest(Username, Password, Apikey, CompanyId);
    <span class="hljs-keyword">var</span> customer = api.CustomerRequest.Get(customerId);
}
</code></pre>
<p>In order to create a new Sage One Customer, you’ll need to create a new instance of the Customer class, as illustrated below:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SaveCustomer</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> api = newApiRequest(Username, Password, Apikey, CompanyId);
    <span class="hljs-keyword">var</span> customer = <span class="hljs-keyword">new</span> Customer
    {
        Name = <span class="hljs-string">"Mr. David R. Robinett"</span>,
        AcceptsElectronicInvoices = <span class="hljs-literal">true</span>,
        Active = <span class="hljs-literal">true</span>,
        AutoAllocateToOldestInvoice = <span class="hljs-literal">true</span>,
        Balance = <span class="hljs-number">0</span>,
        ContactName = <span class="hljs-string">"Mr. David R. Robinett"</span>,
        DeliveryAddress01 = <span class="hljs-string">"Pappelallee 6667"</span>,
        DeliveryAddress02 = <span class="hljs-string">"Solingen"</span>,
        DeliveryAddress03 = <span class="hljs-string">"Nordrhein-Westfalen"</span>,
        DeliveryAddress04 = <span class="hljs-string">"42651"</span>,
        DeliveryAddress05 = <span class="hljs-string">"Germany"</span>,
        CommunicationMethod = <span class="hljs-number">1</span>,
        PostalAddress01 = <span class="hljs-string">"Pappelallee 6667"</span>,
        PostalAddress02 = <span class="hljs-string">"Solingen"</span>,
        PostalAddress03 = <span class="hljs-string">"Nordrhein-Westfalen"</span>,
        PostalAddress04 = <span class="hljs-string">"42651"</span>,
        PostalAddress05 = <span class="hljs-string">"Germany"</span>,
        Telephone = <span class="hljs-string">"238-555-0100"</span>,
        SalesRepresentativeId = <span class="hljs-literal">null</span>
    };
    api.CustomerRequest.Save(customer);
}
</code></pre>
<p>To delete a Sage One Customer, simply call the Delete method:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Delete</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">int</span> customerId = <span class="hljs-number">12345</span>;
    <span class="hljs-keyword">var</span> api = <span class="hljs-keyword">new</span> ApiRequest(Username, Password, Apikey, CompanyId);
    <span class="hljs-keyword">var</span> result = api.CustomerRequest.Delete(customerId);
}
</code></pre>
<p>To create a Tax Invoice:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">CreateInvoice</span>(<span class="hljs-params"></span>)</span>
{
    <span class="hljs-keyword">var</span> api = <span class="hljs-keyword">new</span> ApiRequest(Username, Password, Apikey, CompanyId);
    <span class="hljs-keyword">var</span> customerId = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">var</span> salesRepId = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">var</span> itemId = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">var</span> taxTypeId = <span class="hljs-number">0</span>;
    TaxInvoice invoice = <span class="hljs-keyword">new</span> TaxInvoice();
    <span class="hljs-keyword">var</span> customer = api.CustomerRequest.Get(customerId);
    <span class="hljs-keyword">var</span> salesRep = api.SalesRepresentativeRequest.Get(salesRepId);
    <span class="hljs-comment">// Must set both CustomerId and Customer in order to work</span>
    invoice.CustomerId = customerId;
    invoice.Customer = customer;
    <span class="hljs-comment">// Must set both SalesRepresentativeId and SalesRepresentative in order to work</span>
    invoice.SalesRepresentativeId = salesRepId;
    invoice.SalesRepresentative = salesRep;
    invoice.Date = DateTime.Now;
    invoice.DueDate = <span class="hljs-keyword">new</span> DateTime(<span class="hljs-number">2015</span>, <span class="hljs-number">12</span>, <span class="hljs-number">12</span>);
    invoice.Lines = <span class="hljs-keyword">new</span> List&lt;CommercialDocumentLine&gt;();
    <span class="hljs-keyword">var</span> line1 = <span class="hljs-keyword">new</span> CommercialDocumentLine
    {
        SelectionId = itemId, <span class="hljs-comment">// This must be an item or account id</span>
        TaxTypeId = taxTypeId, <span class="hljs-comment">// Use TaxTypeRequest to get list of Tax Types</span>
        LineType = <span class="hljs-number">0</span>, <span class="hljs-comment">// 0=Item/1=Account</span>
        Quantity = <span class="hljs-number">1</span>,
        UnitPriceExclusive = <span class="hljs-number">390</span>,
        UnitPriceInclusive = <span class="hljs-number">390</span>,
        DiscountPercentage = <span class="hljs-number">0</span>
    };
    invoice.Lines.Add(line1);
    <span class="hljs-keyword">var</span> newTaxInvoice = api.TaxInvoiceRequest.Save(invoice);
}
</code></pre>
<p>Lots more to come. Keep watching this space!</p>
]]></content:encoded></item><item><title><![CDATA[Create South African test data with NBuilder and Faker]]></title><description><![CDATA[I’ve recently read an excellent article by Jerrie Pelser about using NBuilder and Faker.Net to generate test data for your .Net project – something I actually need on a regular basis.
However, I needed data that looked a bit more South African so, I’...]]></description><link>https://mythicalmanmoth.com/create-south-african-test-data-with-nbuilder-and-faker</link><guid isPermaLink="true">https://mythicalmanmoth.com/create-south-african-test-data-with-nbuilder-and-faker</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Sat, 08 Aug 2015 12:08:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/vg3Pv0H9mFA/upload/v1664279347304/OS1tybdJk.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I’ve recently read an excellent <a href="http://www.jerriepelser.com/blog/creating-test-data-with-nbuilder-and-faker">article by Jerrie Pelser</a> about using NBuilder and Faker.Net to generate test data for your .Net project – something I actually need on a regular basis.</p>
<p>However, I needed data that looked a bit more South African so, I’ve added some South African flavour to Faker.Net. You can now generate South African names, surnames, provinces and actual valid ID numbers for use as test data in your project.</p>
<p>In the following example I generate 100 client records with random South African names, surnames, provinces and ID numbers:</p>
<p>You can get the code on <a href="https://github.com/Pietervdw/faker-cs">Github</a>.</p>
<p>Resources used for this article:</p>
<ul>
<li><a href="http://www.jerriepelser.com/blog/creating-test-data-with-nbuilder-and-faker">Create test data with NBuilder and Faker</a> by Jerrie Pelser</li>
<li><a href="http://thinketg.com/how-to-generate-better-random-numbers-in-c-net-2/">How to Generate Better Random Numbers in C#</a> .NET by Ben Klopfer</li>
<li><a href="http://geekswithblogs.net/willemf/archive/2005/10/30/58561.aspx">How to validate SA Identity Numbers</a> by Willem Fourie</li>
<li><a href="http://www.sadev.co.za/content/what-south-african-id-number-made">What is a South African ID number made up of?</a> by Robert MacLean</li>
<li><a href="http://www.name-statistics.org/za/prenumecomune.php">The most common first names in South Africa</a> by <a href="http://www.name-statistics.org">http://www.name-statistics.org</a></li>
<li><a href="http://www.name-statistics.org/za/numedefamiliecomune.php">The most common surnames in South Africa</a> by <a href="http://www.name-statistics.org">http://www.name-statistics.org</a></li>
<li><a href="https://github.com/jonwingfield/Faker.Net">Faker.NET</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Book give-away : Bootstrap for ASP.NET MVC]]></title><description><![CDATA[Stand a chance to win a free copy of Bootstrap for ASP.NET MVC, just by commenting!
This competition is now closed. Winners will be informed via e-mail. Thanks to all for commenting!
For the contest Packt have 3 copies of Bootstrap for ASP.NET MVC, t...]]></description><link>https://mythicalmanmoth.com/book-give-away-bootstrap-for-aspnet-mvc</link><guid isPermaLink="true">https://mythicalmanmoth.com/book-give-away-bootstrap-for-aspnet-mvc</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Thu, 16 Oct 2014 09:40:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664279181044/ip2fd6bNR.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-stand-a-chance-to-win-a-free-copy-of-bootstrap-for-aspnet-mvc-just-by-commenting">Stand a chance to win a free copy of Bootstrap for ASP.NET MVC, just by commenting!</h3>
<h3 id="heading-this-competition-is-now-closed-winners-will-be-informed-via-e-mail-thanks-to-all-for-commenting">This competition is now closed. Winners will be informed via e-mail. Thanks to all for commenting!</h3>
<p>For the contest Packt have 3 copies of <strong>Bootstrap for ASP.NET MVC</strong>, to be given away to 3 lucky winners.</p>
<p><strong>How you can win:</strong></p>
<p>To win your copy of this book, all you need to do is come up with a comment below highlighting the reason "why you would like to win this book”.</p>
<p><strong>Duration of the contest &amp; selection of winners:</strong></p>
<p>The contest is valid for a week from 16 to 24 October 2014, and is open to everyone. Winners will be selected on the basis of their comment posted.</p>
<p><strong>About the book:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664279200483/RBTKT_h2i.png" alt="image.png" /></p>
<p>This book guides you through the process of creating an ASP.NET MVC website from scratch using Bootstrap. You will learn about various Bootstrap components as well as techniques to include them in your own projects. The book includes practical examples to show you how to use open source plugins with Bootstrap and ASP.NET MVC and will guide you through building an ASP.NET MVC website using Bootstrap, utilizing layout and user interface components. In the process, you will also learn to build ASP.NET MVC HTML helpers and T4 templates as well as how to use the jQuery DataTables plugin. At the end of this book, you will find some valuable tips and tricks, which will help you in getting the most out of your Bootstrap and ASP.NET MVC integrated website.</p>
<p>Book is for ASP.NET MVC developer who would like to know how to incorporate Bootstrap into their projects. Developers with entry-level experience of ASP.NET MVC development and limited experience with Bootstrap will also benefit from this book.</p>
<p>Read more about the book on the <a href="http://bit.ly/1B2PK9P">Packt Publishing website</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Bootstrap for ASP.Net MVC Published!]]></title><description><![CDATA[I’m very proud and happy to announce that my book, Bootstrap for ASP.NET MVC has been published and is available for purchase.
This book guides developers on what is Bootstrap, how to include it in your project and even how to create HTML Helpers as ...]]></description><link>https://mythicalmanmoth.com/bootstrap-for-aspnet-mvc-published</link><guid isPermaLink="true">https://mythicalmanmoth.com/bootstrap-for-aspnet-mvc-published</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Thu, 28 Aug 2014 04:37:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664278697374/_QuK2YYjZ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664278720971/kNvnq_qnk.png" alt="image.png" /></p>
<p>I’m very proud and happy to announce that my book, Bootstrap for ASP.NET MVC has been published and is available for purchase.</p>
<p>This book guides developers on what is Bootstrap, how to include it in your project and even how to create HTML Helpers as well as T4 templates to generate Bootstrap ready Razor views.</p>
<p>I hope developers will find it a useful resource, and will enjoy the book as much as I enjoyed writing it.</p>
<p>You can purchase Bootstrap for ASP.NET MVC from the following stores:</p>
<ul>
<li><a href="https://www.packtpub.com/web-development/bootstrap-aspnet-mvc">PACKT Publishing</a></li>
<li><a href="http://www.amazon.com/Bootstrap-ASP-NET-MVC-Pieter-Westhuizen/dp/1783987286/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1409200283&amp;sr=1-1">Amazon.com</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Returning a Crystal report as a PDF ActionResult in ASP.Net MVC]]></title><description><![CDATA[In a recent project I needed to display a generated PDF contract document inside the browser. I found a great article by Patrick Kalkman illustrating how to create a custom ActionResult that converts a HTML string into a PDF using the iTextSharp libr...]]></description><link>https://mythicalmanmoth.com/returning-a-crystal-report-as-a-pdf-actionresult-in-aspnet-mvc</link><guid isPermaLink="true">https://mythicalmanmoth.com/returning-a-crystal-report-as-a-pdf-actionresult-in-aspnet-mvc</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Fri, 18 Jul 2014 08:41:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/780J1cI0Byc/upload/v1664278186399/824nmmQL7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In a recent project I needed to display a generated PDF contract document inside the browser. I found a <a href="http://www.codeproject.com/Articles/260470/PDF-reporting-using-ASP-NET-MVC">great article by Patrick Kalkman</a> illustrating how to create a custom ActionResult that converts a HTML string into a PDF using the iTextSharp library.</p>
<p>This seemed like the perfect solution, however, I later found that the conversion from HTML to PDF is not perfect at all and getting your design to look the same in PDF as it does in HTML is not easy. So I found another <a href="http://hasibulhaque.com/index.php/2011/crystal-report-asp-net-mvc/">article by Hasibul Haque</a>, where he shows how to return a Crystal Report as PDF using ASP.Net MVC.</p>
<p>The Crystal Report approach works well, as your design will look perfect. The only problem I had was Hasibul’s approach returned the PDF as a download and I wanted to display it inside the browser. I combined Patrick and Hasibul’s approaches and what I came up with was a <strong>CrystalReportPdfResult</strong></p>
<p>The CrystalReportPdfResult is an ASP.Net ActionResult, that return the Crystal Report as a PDF file. The result (using an iframe) looks like this inside the browser:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664278218642/Tpd6xP318.png" alt="image.png" /></p>
<h4 id="heading-creating-the-crystalreportpdfresult-class">Creating the CrystalReportPdfResult class</h4>
<p>To generate the result as indicated by the previous image, follow these steps:</p>
<ol>
<li>Create a folder inside your ASP.Net MVC project called <strong>Pdf</strong>.</li>
<li>Add a new class to this folder called <strong>CrystalReportPdfResult.cs</strong>.</li>
<li>The new class will inherit from the ASP.Net MVC <strong>ActionResult</strong> class.</li>
</ol>
<p>The entire code listing for the CrystalReportPdfResult class follows:</p>
<p>CrystalReportPdfResult.cs</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CrystalReportPdfResult</span> : <span class="hljs-title">ActionResult</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">byte</span>[] _contentBytes;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CrystalReportPdfResult</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> reportPath, <span class="hljs-keyword">object</span> dataSet</span>)</span>
    {
        ReportDocument reportDocument = <span class="hljs-keyword">new</span> ReportDocument();
        reportDocument.Load(reportPath);
        reportDocument.SetDataSource(dataSet);
         _contentBytes = StreamToBytes(reportDocument.ExportToStream(ExportFormatType.PortableDocFormat));
     }

     <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ExecuteResult</span>(<span class="hljs-params">ControllerContext context</span>)</span>
     {

         <span class="hljs-keyword">var</span> response = context.HttpContext.ApplicationInstance.Response;
         response.Clear();
         response.Buffer = <span class="hljs-literal">false</span>;
         response.ClearContent();
         response.ClearHeaders();
         response.Cache.SetCacheability(HttpCacheability.Public);
         response.ContentType = <span class="hljs-string">"application/pdf"</span>;

         <span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> stream = <span class="hljs-keyword">new</span> MemoryStream(_contentBytes))
         {
             stream.WriteTo(response.OutputStream);
             stream.Flush();
         }
     }

     <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">byte</span>[] <span class="hljs-title">StreamToBytes</span>(<span class="hljs-params">Stream input</span>)</span>
     {
         <span class="hljs-keyword">byte</span>[] buffer = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[<span class="hljs-number">16</span> * <span class="hljs-number">1024</span>];
         <span class="hljs-keyword">using</span> (MemoryStream ms = <span class="hljs-keyword">new</span> MemoryStream())
         {
             <span class="hljs-keyword">int</span> read;
             <span class="hljs-keyword">while</span> ((read = input.Read(buffer, <span class="hljs-number">0</span>, buffer.Length)) &gt; <span class="hljs-number">0</span>)
             {
                 ms.Write(buffer, <span class="hljs-number">0</span>, read);
             }
             <span class="hljs-keyword">return</span> ms.ToArray();
         }
     }
 }
</code></pre>
<h4 id="heading-creating-the-crystal-report">Creating the Crystal Report</h4>
<p>Next, we need to create the Crystal Report that will be returned as a PDF. Do this by following these steps:</p>
<ol>
<li>Create a new folder called <strong>Reports</strong> in your project.</li>
<li>Add a new Crystal Report object to the <strong>Reports</strong> folder. You can find the item template under the <strong>Reporting</strong> tab on the Add New Item dialog.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664278282639/whD060PhG.png" alt="image.png" /></li>
<li>Design the report to your liking and save it.</li>
<li>If you need to install Crystal Reports for Visual Studio 2013, get it <a href="http://scn.sap.com/docs/DOC-7824">here</a>.</li>
</ol>
<h4 id="heading-creating-the-action-that-will-return-the-pdf">Creating the Action that will return the PDF</h4>
<p>Next, we need to create the actual Action on a Controller that will return the CrystalReportPdfResult, by following these steps:</p>
<ol>
<li>Open your controller. In this example, we’ll use the <strong>HomeController</strong>.</li>
<li>Add a new method called <strong>Pdf</strong> that will return a <strong>CrystalReportPdfResult</strong> object.</li>
<li>Inside this method, we’ll build a list of customer that will be used as data for the report and build the path to the report filename. The code for the method follows:</li>
</ol>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> CrystalReportPdfResult <span class="hljs-title">Pdf</span>(<span class="hljs-params"></span>)</span>
{
    List&lt;Customer&gt; model = <span class="hljs-keyword">new</span> List&lt;Customer&gt;();
    model.Add(<span class="hljs-keyword">new</span> Customer { CompanyName = <span class="hljs-string">"Blah Inc."</span>, ContactName = <span class="hljs-string">"Joe Blogs"</span> });
    <span class="hljs-keyword">string</span> reportPath = Path.Combine(Server.MapPath(<span class="hljs-string">"~/Reports"</span>), <span class="hljs-string">"rptCustomers.rpt"</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> CrystalReportPdfResult(reportPath, model);
}
</code></pre>
<h4 id="heading-creating-the-view">Creating the View</h4>
<p>We’ll embed the PDF using an <strong><iframe></iframe></strong>, so open a view. In this case we’ll  use <strong>About.cshtml</strong> and replace it’s mark-up with the following:</p>
<p>About.cshtml</p>
<pre><code class="lang-razor">@{
    ViewBag.Title = "Customer Report";
}
&lt;h2&gt;@ViewBag.Title.&lt;/h2&gt;
&lt;p&gt;This is the customer report&lt;/p&gt;

&lt;div class="row"&gt;
    &lt;div class="col-md-10"&gt;
         &lt;iframe src="@Url.Action("Pdf", "Home")" height="500" width="100%"&gt;&lt;/iframe&gt;
     &lt;/div&gt;
     &lt;div class="col-md-2"&gt;
         &lt;h3&gt;Other page content&lt;/h3&gt;
         &lt;button type="button" class="btn btn-primary"&gt;Click here&lt;/button&gt;
     &lt;/div&gt;
 &lt;/div&gt;
</code></pre>
<p>Note, that we’re using the <strong>@Url.Action</strong> helper to set the <strong>src</strong> attribute of the <iframe> element. This will make a call to the <strong>Pdf</strong> action on the <strong>Home</strong> controller and render the result inside the <strong><iframe></iframe></strong></iframe></p>
<p>In case you’re wondering how to send the Crystal Report as a PDF attachment on an email, here is the code:</p>
<p>Code Snippet</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SendReport</span>(<span class="hljs-params"></span>)</span>
        {
            List&lt;Customer&gt; model = <span class="hljs-keyword">new</span> List&lt;Customer&gt;();
            model.Add(<span class="hljs-keyword">new</span> Customer { CompanyName = <span class="hljs-string">"Blah Inc."</span>, ContactName = <span class="hljs-string">"Joe Blogs"</span> });

            ReportDocument reportDocument = <span class="hljs-keyword">new</span> ReportDocument();
            reportDocument.Load(Path.Combine(Server.MapPath(<span class="hljs-string">"~/Reports"</span>), <span class="hljs-string">"rptCustomers.rpt"</span>));
            reportDocument.SetDataSource(model);
            <span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> stream = reportDocument.ExportToStream(ExportFormatType.PortableDocFormat))
             {
                 SmtpClient smtp = <span class="hljs-keyword">new</span> SmtpClient
                 {
                     Port = <span class="hljs-number">587</span>,
                     UseDefaultCredentials = <span class="hljs-literal">true</span>,
                     Host = <span class="hljs-string">"smtp.gmail.com"</span>,
                     EnableSsl = <span class="hljs-literal">true</span>
                 };

                 smtp.UseDefaultCredentials = <span class="hljs-literal">false</span>;
                 smtp.Credentials = <span class="hljs-keyword">new</span> NetworkCredential(<span class="hljs-string">"you@gmail.com"</span>, <span class="hljs-string">"gmailPassword"</span>);

                 <span class="hljs-keyword">var</span> message = <span class="hljs-keyword">new</span> System.Net.Mail.MailMessage(<span class="hljs-string">"you@gmail.com"</span>, <span class="hljs-string">"recipient@gmail.com"</span>, <span class="hljs-string">"subject"</span>, <span class="hljs-string">"body"</span>);
                 message.Attachments.Add(<span class="hljs-keyword">new</span> Attachment(stream, <span class="hljs-string">"report.pdf"</span>));

                 smtp.Send(message);
             }
         }
</code></pre>
<p>I’ve tested this on the latest version of Chrome, Firefox and Internet Explorer and it works on all of them.</p>
<p>Hope this helps someone that needs something similar. Thank you for reading. Until next time, keep coding!</p>
<p>Download the sample project <a href="https://www.dropbox.com/s/gonervde3avxkgb/PdfSample.zip?dl=0">here.</a></p>
<p>If you have any comments or questions, please feel free to ask leave a comment or drop me a line on <a href="http://twitter.com/pietervander">Twitter</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Writer Boot camp #1 – Even if you know me well, you don’t know this]]></title><description><![CDATA[Even if you know me well, you don’t know this." Jack said as he slowly withdrew the knife from his doctors’ bag. "I used to be a surgeon once, a man before my time. They ridiculed and scoffed at my unorthodox approach, they said I was insane."
"Findi...]]></description><link>https://mythicalmanmoth.com/writer-boot-camp-1-even-if-you-know-me-well-you-dont-know-this</link><guid isPermaLink="true">https://mythicalmanmoth.com/writer-boot-camp-1-even-if-you-know-me-well-you-dont-know-this</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Tue, 01 Jul 2014 07:31:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/Ty6BwyTxVF4/upload/v1664277985845/evqOOCd7H.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664277960421/iDo5NxJMo.png" alt="image.png" />
Even if you know me well, you don’t know this." Jack said as he slowly withdrew the knife from his doctors’ bag. "I used to be a surgeon once, a man before my time. They ridiculed and scoffed at my unorthodox approach, they said I was insane."</p>
<p>"Finding solace at the bottom of a bottle and comfort in the arms of harlots, my true genius lost in the annals of history", he fumed whilst arranging his tools of the trade. "Well, they will know of me, speak of me in hushed tones."</p>
<p>The calmness in his voice was almost reassuringly confident, a bedside manner that instilled confidence and trust. "You see my dear, the unfortunate ones are discarded by society, but I discovered their true potential. Through our many encounters I came to the realization that despite our different social standing, we all want, nay, need the same thing." he said, his voice taking on an ominous tone. "We all crave acceptance and I, I crave knowledge above all else, and knowledge of human anatomy more so."</p>
<p>My dear Mary Jane, even if you know me well, you did not know this."</p>
<blockquote>
<p><a href="https://twitter.com/Writersbootcmp">Writers Boot camp</a> – commit to write an post in 60 minutes every day of July 2014.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Microsoft Outlook Email Templates for Web Designers and Developers Add-in]]></title><description><![CDATA[Bea Kylene Jumarang wrote a great piece listing some very handy email templates for web developers and designers.I found the information so valuable I could not help but create a Microsoft Outlook (2007, 2010 and 2013) Add-in that automatically inser...]]></description><link>https://mythicalmanmoth.com/microsoft-outlook-email-templates-for-web-designers-and-developers-add-in</link><guid isPermaLink="true">https://mythicalmanmoth.com/microsoft-outlook-email-templates-for-web-designers-and-developers-add-in</guid><dc:creator><![CDATA[Pieter van der Westhuizen]]></dc:creator><pubDate>Fri, 27 Jun 2014 13:55:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/oIpJ8koLx_s/upload/v1664277863772/EFOBSPaAz.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://twitter.com/beajumarang">Bea Kylene Jumarang</a> wrote a great piece listing some very handy <a target="_blank" href="http://www.smashingmagazine.com/2013/06/20/email-templates-web-designers-developers-pdf-odt-txt/">email templates for web developers and designers</a>.<br />I found the information so valuable I could not help but create a Microsoft Outlook (2007, 2010 and 2013) Add-in that automatically inserts the templates for you. It’s released under the GNU General Public License, which means it is <strong><em>completely free for you to use and share with your friends and colleagues</em></strong>.</p>
<p>Thanks Bea!</p>
<p>Download the add-in <a target="_blank" href="https://www.dropbox.com/s/acsnh5a1e3hfycc/EmailTemplatesForDevsAndDesigners.msi?dl=0">here</a>.</p>
<blockquote>
<p>Note that the actual templates are free for commercial and personal use, but you’re not allowed to sell it or claim it as your own. So for the sake of complete disclosure, I did not create the templates, I only created the Outlook add-in that automatically inserts the template text into your Outlook e-mail.</p>
</blockquote>
<h5 id="heading-how-it-works">How it works</h5>
<p>The add-in adds a new <em>“Templates for Developers and Designers”</em> tab to the Outlook E-mail window:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665492131749/eXXZ9JjFn.png" alt="image_thumb2.png" /></p>
<p>Clicking on the <em>“Insert Template”</em> button lists all the available templates:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664277717738/qywOHCz9_.png" alt="image.png" /></p>
<p>Clicking on the template name, automatically inserts the template into the e-mail. If the e-mail has a recipient the recipient’s name will automatically be inserted into the e-mail as well:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664277731967/3xRKWleHy.png" alt="image.png" /></p>
<p>This functionality will work when composing a new e-mail and when replying to an existing mail.</p>
<h5 id="heading-the-templates">The Templates</h5>
<p>All the templates are stored inside your <strong>My Documents</strong> folder inside a folder called <strong>TemplatesForDevsAndDesigners.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664277750143/di1w-6eVm.png" alt="image.png" /></p>
<p>Each template has its own folder and inside this folder the actual template called template.html. You can edit this .html file in any text editor to customize the template to your liking.</p>
<p>It’s as easy as that. I hope you find the add-in useful.  Any comments, suggestions or bug reports, fire away in the comments or get in touch with me<br />on <a target="_blank" href="https://twitter.com/pietervander">Twitter</a>.</p>
<p>You can download the add-in <a target="_blank" href="https://www.dropbox.com/s/acsnh5a1e3hfycc/EmailTemplatesForDevsAndDesigners.msi?dl=0">here</a>.</p>
]]></content:encoded></item></channel></rss>