Verb DELETE Return 405

Hari ini teman saya ada masalah, verb ‘Delete’ pada Web Api mengembalikan 405 pada server Dev. Akhirnya kami menemukan 2 solusi.

  1.  IIS-> click {nama_website} -> click Handler Mappings -> pilih WebDAV kemudian click button Request Restrictions. Pilih All Verbs

web_dav

  1. Pada WebConfig tambahkan handler pada <system.webServer>.
<modules runAllManagedModulesForAllRequests="true">
    <remove name="WebDAVModule"/> <!-- add this -->
</modules>
 dan pada handle section, tambahkan
<handlers>
    <remove name="WebDAV" />
    ...
</handlers>

Akal vs Wahyu

Ada seorang laki-laki yang tersandung dan terjatuh ke dalam sebuah sumur. Untungnya dia sempat meraih sebuah akar yg kuat sehingga menghentikan jatuhnya.
Semakin lama, pegangannya semakin lemah dan dalam keputusasaannya dia berteriak, “Apakah ada orang di atas sana?”
Tiba-tiba sebuah sinar menerobos ke bawah meneranginya. Terdengar suara dari atas, “Saya, Tuhan, ada di sini. Lepaskan akarnya, dan saya akan menolongmu!”.
Laki-laki itu berpikir sejenak dan kemudian berteriak, “Adakah orang lain di atas sana?”.

Etika dan Hukum Ilahi

Malam ini saya membaca buku pengantar filsafat. Pada bab Etika, ketika membahas tentang bagaimana hukum Ilahi menyederhanakan etika. Muncul pertanyaan, bagaimana kita yakin bahwa yang tertulis di kitab suci secara harfiah (tekstual) adalah maksud Tuhan yang sebenarnya?

Saya langsung teringat kisah yang sering dikhutbahkan ketika hari Kurban. Tentang bagaimana Nabi Ibrahim as mendapatkan perintah dari Tuhan lewat mimpinya untuk menyembelih anak kesayangannya Ismail as atau dilain versi Ishaq as. Perintah ini walaupun secara etika tidak masuk akal dan terkesan ‘gila’ karena merampas hak hidup, Ibrahim walaupun berat hati tetap melaksanakannya. Tindakan Ibrahim ini adalah bukti bahwa ketaatannya kepada Tuhan lebih besar daripada kasih sayangnya kepada anak. Kemudian ternyata, Tuhan menggantikan kurbannya dengan seekor domba.
Nah, ada yang menarik. Saya pernah baca bahwa Ibnu Arabi -seorang filsuf dan sufi besar berpendapat bahwa seandainya Ibrahim as melakukan takwil atas mimpinya, dia bisa menangkap pesan metaforis dari Tuhan bukannya arti harfiahnya, maka perintah ini tidak akan berat dan berkesan seolah melanggengkan tradisi pagan yang mengurbankan jiwa manusia.

Wallahu A’lam Bishawab.

Binding ListView using MvvmCross in Xamarin

Melanjutkan project pada tulisan MVVM Pattern in Xamarin Project using MvvmCross.

Kita buat sebuah class Book di Portable project.

public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string Image { get; set; }
public string Author { get; set; }
public decimal Price { get; set; }
public int Year { get; set; }
}

Kemudian kita buat lagi sebuah ViewModel. ViewModel yang digunakan pada ListView harus berisi setidaknya sebuah ObservableCollection. Di konstruktor kita inisialisasi data untuk ObservableCollection Items.

public class BookViewModel : MvxViewModel
{
public ObservableCollection Items { get; set; }
public BookViewModel()
{
Items = new ObservableCollection();
Items.Add(
new Book
{
Id = 1,
Title = "Lord Of The Ring",
Author = "JJR. TOLKIEN",
Price = 40,
Year = 2001,
Image = "https://luckty.files.wordpress.com/2012/05/b32.jpg"
});
Items.Add(
new Book
{
Id = 2,
Title = "The Hobbit",
Author = "JJR. TOLKIEN",
Price = 35,
Year = 2014,
Image = "https://images-na.ssl-images-amazon.com/images/I/41aQPTCmeVL._SX331_BO1,204,203,200_.jpg"
});

}
}

Selanjutanya pada project .Droid (android) kita buat sebuah Layout (.axml), sebagai contoh kita beri nama BookListView.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Mvx.MvxListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        local:MvxItemTemplate="@layout/row_layout"
        local:MvxBind="ItemsSource Items">
</LinearLayout>

Perhatikan local:MvxBind=”ItemsSource Items”, artinya kita melakukan Binding data pada ListView dari property Items pada class Book. Sedangkan  untuk menentukan template pada ListView kita gunakan  local:MvxItemTemplate.

Pada folder Layout buat sebuah AndroidLayout (.axml) dengan nama row_layout.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="8dp">
    <LinearLayout
        android:id="@+id/Text"
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="10dip">
        <TextView
            android:id="@+id/Text2"
            android:layout_width="wrap_content"
            android:layout_height="15.0dp"
            android:textSize="14dip"
            android:paddingLeft="100dip"
            local:MvxBind="Text Title" />
    </LinearLayout>
    <Mvx.MvxImageView
        android:layout_width="78.0dp"
        android:layout_height="82.5dp"
        android:padding="5dip"
        local:MvxBind="ImageUrl Image" />
</RelativeLayout>

Perhatikan kita melakukan binding Image dengan menggunakan; ItemLongClick ShowInfo”local:MvxBind=”ImageUrl Image” yang artinya ImageUrl pada grid di set dari properti Image pada class Book.

Selanjutnya kita buat sebuah activity yang merupakan turunan dari  MvxActivity kemudian pada generic parameternya kita set model yang akan dipanggil yaitu BookViewModel. Jangan lupa set content viewnya dari Layout BookListView.

[Activity(Label = "Book List", MainLauncher = true)]
public class BookView : MvxActivity<BookViewModel>
{
protected override void OnViewModelSet()
{
base.OnViewModelSet();
SetContentView(Resource.Layout.BookListView);
}
}

Kita running emulator android kita

mvvm_book_emulator.png

Sekarang kita tambahkan event ketika ListView item di click dengan agak lama. Event ini akan memunculkan user dialog alert info tambahan dari Book. Kita tambahkan sebuah ICommand property pada class Book.

public ICommand ShowInfo
{
get
{
return new MvxCommand(b => Mvx.Resolve().Alert(GetInfo(b)));
}

}

protected string GetInfo(Book book)
{
var output = new StringBuilder();
output.Append($"Author: {book.Author}");
output.AppendLine();
output.Append($"Year: {book.Year}");
output.AppendLine();
output.Append($"Price: {book.Price}");
return output.ToString();
}

ShowInfo kita bind sebagai event ketika ListView item click sehingga layout dari BookListView jadi seperti ini.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Mvx.MvxListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        local:MvxItemTemplate="@layout/row_layout"
        local:MvxBind="ItemsSource Items; ItemLongClick ShowInfo" />
</LinearLayout>

Untuk UserDialog kita menggunakan plugin ACR User Dialogs. Install lewat Nuget package manager console.

PM > Install-Package Acr.UserDialogs

Jangan lupa pada class App.cs di .Portable project register instance dari IUserDialog.

Mvx.RegisterSingleton(UserDialogs.Instance);

_user_dialog_xamarin.png

MVVM Pattern in Xamarin Project using MvvmCross

Salah satu jenis pattern yang sering digunakan pada pengembangan aplikasi dekstop dan mobile dalah Model-View View Model. Seperti pattern MVC, MVVM juga memisahkan application logic dan User Interface sehingga aplikasi akan lebih mudah ditest, dimaintenance  dan dikembangkan.

Ada 3 komponen yaitu: model, view dan view model. Masing-masing memiliki peran dan tanggung jawab yang berbeda seperti diilustrasikan pada gambar berikut ini.

ic564167

Kita akan membuat project sederhana menggunakan Xamarin. Pilih Cross-Platform->Portable project

mvvmcross1

Kita akan melihat ada 3 project, portable, android dan ios.

MvvmCross2.png

Kita akan rename BookStoreMvvm.Core.Droid menjadi BookStoreMvvm.UI.Droid. Selanjutnya lewat nuget, install MvvmCross.Core

MvvmCross4.png

Pada project .Portable kita buat sebuah interface untuk service.

public interface ICalculatorService
{
int Add(int number1, int number2);
}

Kemudian class Implementasinya.

public class CalculatorService : ICalculatorService
{
public int Add(int number1, int number2)
{
return number1 + number2;
}
}

Sekarang kita buat sebuah class View Model yang inherit dari class MvxViewModel, karena dalam MvvmCross semua View Model harus merupakan class turunan dari MvxViewModel.

public class CalculatorViewModel : MvxViewModel
{
ICalculatorService _calculatorService;
public CalculatorViewModel(ICalculatorService calculatorService)
{
_calculatorService = calculatorService;
}
public override void Start()
{
Add();
base.Start();
}

int _operand1;
public int Operand1
{
get { return _operand1; }
set
{
_operand1 = value;
Add();

}
}

int _operand2;
public int Operand2
{
get { return _operand2; }
set
{
_operand2 = value;
Add();

}
}
int _result;
public int Result
{
get { return _result; }
set {
_result = value;
RaisePropertyChanged(() => Result);
}
}

private void Add()
{
Result = _calculatorService.Add(_operand1, _operand2);
}
}

RaisePropertyChanged(), artinya kita memberikan notifikasi bahwa sebuah property telah berubah sehingga pada UI nilainya akan disesuaikan dengan perubahan. Jadi sini, jika property Result di set pada setiap pemanggilan method Add(), maka nilai result pada UI akan ikut berubah.

Karena pada class di atas kita menggunakan dependency injection -yaitu dengan melewatkan tipe ICalculatorService pada konstruktor, kita perlu meregistrasi interface dan class implementasinya disebuah class App. Class App ini juga akan menentukan ViewModel mana yang akan digunakan saat Start.

public class App : MvxApplication
{
public App()
{
Mvx.RegisterType<ICalculatorService, CalculatorService>();
Mvx.RegisterSingleton(new MvxAppStart());
}
}

Selanjutnya pada project .Droid kita hapus MainActivity dan Main.axml. Kita tidak membutuhkan file-file itu lagi.

mvvm_34.png

Selanjutnya buatlah class Setup untuk melakukan inisialiasi framework MvvmCross pada project android kita. Untuk android, class Setup harus merupakan turunan dari MvxAndroidSetup.

public class Setup : MvxAndroidSetup
{
public Setup(Context applicationContext) : base(applicationContext)
{
}

protected override IMvxApplication CreateApp()
{
return new App();
}
}

Kemudian kita buat sebuah layout (.axml) seperti ini.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res/BookStoreMvvm.UI.Droid"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        local:MvxBind="Text Operand1" />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        local:MvxBind="Text Operand2" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        local:MvxBind="Text Result" />
</LinearLayout>

local:MvxBind artinya field ui yang kita buat akan melakukan binding dengan property sebuah ViewModel.

Selanjutanya kita buat sebual class view (kalau pada Xamarin Form kita menyebutnya Activity), yang merupakan turunan dari MvxActivity. Kita tambahkan attribut activity sebagai main launcer agar class ini diekseskusi sebagai main activity.

[Activity(Label = "Calculator", MainLauncher = true)]
public class CalculatorView : MvxActivity
{
public new CalculatorViewModel ViewModel
{
get { return (CalculatorViewModel)base.ViewModel; }
set { base.ViewModel = value; }
}

protected override void OnViewModelSet()
{
base.OnViewModelSet();
SetContentView(Resource.Layout.Calculator);
}
}

Kita running android project kita.mvvm_show.png

Selanjutnya kita  ganti nilai dari field pertama (binding : Operand1) dan kedua(binding: Operand2). Terlihat bahwa nilai field ketiga(binding:Result) nilainya merupakan nilai penambahan field pertama dan kedua.

mvvm_show1.png

Menulis Buku Pemrograman

Salah satu resolusi saya tahun ini selain hidup lebih sehat dan mengurangi menatap layar gadget di rumah, adalah menulis buku. Setelah tiga bulan menulis sedikit demi sedikit di akhir pekan, sekarang progressnya sudah mencapai 80%.

Saya menulis buku berawal dari melihat kurangnya buku pemrograman di Indonesia yang membahas hal-hal yang konseptual seperti prinsip-prinsip menulis dan mendesain program yang baik. Walaupun saya tahu, saya harus masih banyak belajar lagi mengenai topik itu. Ya anggaplah, buat pemacu belajar juga. Semakin kita bisa menjelaskan sesuatu secara sederhana, semakin kita mengerti apa yang kita sampaikan.

Jujur saya gak bisa mendesign, jadi saya pakai template yang ada di MS Office aja. Anggap saja cover buku sementaras selagi menunggu ada yang berbaik hati mendesignkan cover bukunya :). Semoga bulan depan sudah bisa direlease.

cover_book

 

Basic Regular Expression

Regular Expression wajib diketahui oleh seorang programmer karena seringkali digunakan untuk mencari atau memvalidasi sebuah string. Regular Expression hampir bisa digunakan di semua bahasa pemrograman. Khusus untuk C#, contoh penggunaannya seperti ini:

Regex regex = new Regex(@"\d+ files? found\?");
var word = "1 file found?";
Match match = regex.Match(word);
Console.WriteLine($"{word} is match ? {match.Success}");

Beberapa basic ekspresi Regular Expression yang paling sering digunakan yang saya rangkum dari  Regexone

Semua string yang mengandung “abc”

abc

Task Text
Match abcd123
Match 123abc4
Skip abd
Skip bcd

Semua string yang didahului oleh karakter”c” atau “m” dan diakhir oleh “an”.

[cm]an 

Semua string yang didahului oleh selain karakter “f” dan diakhir oleh “an”.

[^f]an

Task Text
Match can
Match man
Skip fan

Semua string yang di awali -case sensitif dengan karakter pertama adalah “A” sampai “C”, karater kedua adalah “n” sampai “p” dan karakter ketiga adalah “a” sampai “c”

[A-C][n-p][a-c]

Task Text
Match Ana
Match Bob
Match Cpc
Skip aax
Skip bby
Skip ccz

Semua string yang diawali dengan “wa” dan setelah itu memiliki minimal 3 dan maksimal  4 karater “z” dan diakhiri oleh “up”.

waz{3,4}up

Task Text
Skip wazzzzzup
Match wazzzzup
Match wazzzup
Skip wazup

Semua string yang diawali oleh minimal 2 dan maksimal 4 karakter “a” setelah itu maksimum 4 karakter “b” (karakter b bisa tidak ada) dan minimum 1 dan maksimum 2 karakter “c”.

a{2,4}b{0,4}c{1,2}

Task Text
Match aaaabcc
Match aabbbbc
Match aacc
Skip a
Skip ab
Skip bc

Semua string yang didahului oleh karakter angka, kemudian “file” atau “files” disusul “found?”. Metakarakter “?” menunjukkan optional dan metakarakter “\d” mewakili angka.

\d+ files? found\?

Task Text
Match 1 file found?
Skip 1 file found
Match 2 files found?
Skip No files found

Semua string yang di dahului oleh angka kemudian titik setelah itu whitespace diikuti “abc”. White space diwakili oleh metakarakter “\s”

\d.\s+abc

Task Text
Match 1.       abc
Match 2.           abc
Match 3.               abc
Skip 4.abc

Semua string yang mengandung persis keseluruhan “Mission: successful”. Metakarakter “^” artinya didahului oleh dan “$” artinya diakhiri oleh.

^Mission: successful$ 

Task Text
Match Mission: successful
Skip Last Mission: unsuccessful
Skip Next Mission: successful upon capture of target

Mencapture string yang diawali dengan “file” dan diakhiri dengan “.pdf”. Metakarakter () mencapture group karakter yang diapit olehnya.

^(file.+).pdf$

Task Text Capture Group
Capture file_record_transcript.pdf file_record_transcript
Capture file_07241999.pdf file_07241999
Skip testfile_fake.pdf.tmp

 

 

Menangani Error: The provided anti-forgery token was meant for a different claims-based user than the current user.

Hari ini saya mendapatkan ticket dari Tester mengenai error authentikasi user. Test case nya seperti ini.

  1. Navigasi ke halaman Login di tab pertama, login sebagai user ‘A’.
  2. Kemudian buka tab baru pada browser, buka home page (selain halaman login).
  3. Logout user di tab pertama.
  4. Buka halaman lain pada tab 2, page akan redirect ke halaman login dengan membawa serta query string return url.
  5. Login di tab pertama.
  6. ketika login di tab kedua akan muncul error “The provided anti-forgery token was meant for a different claims-based user than the current user”.

Pertama saya mencoba dengan menonaktifkan cache pada action login  dengan menambahkan attribut [OutputCache(NoStore = true, Location = OutputCacheLocation.None)] tapi ternyata hasil nya tetap sama.

Cara kedua, yaitu dengan cara menghilangkan [ValidateAntiForgeryToken] pada action login, tapi tetap menambahkan  @Html.AntiForgeryToken() pada form. Tapi cara ini malah mengurangi tingkat keamanan pada website.

Akhirnya, setelah googiling. Saya menemukan solusi yang lebih tepat dengan cara membuat attribute untuk menangani error tersebut. Sehingga jika terjadi error tersebut bisa dialihkan ke halaman lain.

public class AntiForgeryHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext context)
{
if (context.Exception is HttpAntiForgeryException)
{
var url = string.Empty;
if (!context.HttpContext.User.Identity.IsAuthenticated)
{
var requestContext = new RequestContext(context.HttpContext, context.RouteData);
url = RouteTable.Routes.GetVirtualPath(requestContext, new RouteValueDictionary(new { Controller = "User", action = "Login" })).VirtualPath;
}
else
{
context.HttpContext.Response.StatusCode = 200;
context.ExceptionHandled = true;
url = GetRedirectUrl(context);
}
context.HttpContext.Response.Redirect(url, true);
}
else
{
base.OnException(context);
}
}

private string GetRedirectUrl(ExceptionContext context)
{
try
{
var requestContext = new RequestContext(context.HttpContext, context.RouteData);
var url = RouteTable.Routes.GetVirtualPath(requestContext, new RouteValueDictionary(new { Controller = "Home", action = "Index" })).VirtualPath;

return url;
}
catch (Exception)
{
throw new NullReferenceException();
}
}

Tambahkan attribute tersebut pada login action

[HttpPost]
       [AllowAnonymous]
       [ValidateAntiForgeryToken]
       [AntiForgeryHandleError]
       public async Task Login(LoginViewModel model, string returnUrl)
       {

Behavior Driven Development (BDD) Using SpecFlow

Behavior Driven Development (or BDD) is an Agile software development technique that encourages collaboration between developers, QA, and non-technical or business participants in a software project. 

Dalam BDD kita menggunakan aspek Given/When/Then ketika membuat Feature. Dari Feature ini,  Tester dapat membuat scenario test. Sedangkan  bagi Developer bisa digunakan untuk membuat Unit Testing. Hindari menggunakan terlalu banyak istilah teknis di dalam feature yang kita buat. Salah satu tujuan menggunakan BDD adalah agar menghindari salah pengertian mengenai sebuah feature antara tester, analis dan developer. Kita akan menggunakan SpecFlow sebagai framework BDD kita.

Sebagai contoh kita mempunyai story seperti ini. Story ini dibuat menggunakan SpecFlow feature file.

Feature: Add Vehicle
    As an Administrator
    I want to be to add new vehicle
    In order to a Customer can reserve it

@mytag
Scenario: Vehicle Name is not blank
    Given I have entered '' into the field name
    When I press Submit
    Then I see message saying name is mandatory

Kemudian klik kanan file feature yang kita buat untuk membuat step.

right_click_generate_steps

steps_bdd.png

SpecFlow akan menghasilkan file steps seperti ini.

using System;
using TechTalk.SpecFlow;

namespace BDDTest
{
[Binding]
public class AddVehicleSteps
{
[Given(@"I have entered '(.*)' into the field name")]
public void GivenIHaveEnteredIntoTheFieldName(string p0)
{
ScenarioContext.Current.Pending();
}

[When(@"I press Submit")]
public void WhenIPressSubmit()
{
ScenarioContext.Current.Pending();
}

[Then(@"I see message saying name is mandatory")]
public void ThenISeeMessageSayingNameIsMandatory()
{
ScenarioContext.Current.Pending();
}
}
}

Kita running unit step tersebut, terlihat bahwa unit tersebut diskip karena belum ada implementasi di dalamnya.

skipped_test.png

Kita akan membuat class untuk menghandle bisnis logic untuk feature tersebut dan memodifikasi class steps di atas.

using BDDProject;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using TechTalk.SpecFlow;

namespace BDDTest
{
[Binding]
public class AddVehicleSteps
{
private IVehicleBLL _vechileBll = new VehicleBLL();
private Vehicle _vehicle = new Vehicle();
private string _message;
[Given(@"I have entered '(.*)' into the field name")]
public void GivenIHaveEnteredIntoTheFieldName(string EmptyName)
{
_vehicle.Name = EmptyName;
}

[When(@"I press Submit")]
public void WhenIPressSubmit()
{
try
{
_vechileBll.Add(_vehicle);
}
catch (Exception ex)
{
_message = ex.Message;
}
}

[Then(@"I see message saying name is mandatory")]
public void ThenISeeMessageSayingNameIsMandatory()
{
Assert.AreEqual(_message.ToLower(), "name is mandatory");
}
}
}

Kita jalankan lagi unit test kita, dan hasilnya seperti ini.

bdd_output.png