CategoriesProgramming

Pemetaan obyek dengan AutoMapper pada ASP .Net Core 3.1

AutoMapper adalah object to object mapper yang memetakan obyek A menjadi obyek B yang memiliki properti dan tipe yang berbeda. Seperti contoh kita perlu melakukan pemetaan Data Transfer Object ke object model. AutoMapper memudahkan proses pemetaan konvensional yang harus memetakan secara manual satu per satu.

Untuk menggunakan AutoMapper pada ASP .Net Core 3.1 terlebih dahulu harus menginstal AutoMapper melalui NuGet atau command pada NuGet Package Manager seperti ini.

Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

Install AutoMapper.Extensions.Microsoft.DependencyInjection, bukan AutoMapper. Karena tujuan kita adalah membuat AutoMapper bisa digunakan diluar dari Startup.cs yang mana di dalam package itu sudah ada AutoMapper.

Setelah install, kita tambahkan di Startup.cs seperti ini.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
    services.AddControllers();
}

Dalam contoh ini saya akan memakai model WeatherForecast hasil dari create project di ASP .Net Core 3.1 Web API.

public class WeatherForecast
{
    public DateTime Date { get; set; }
    public int TemperatureC { get; set; }
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    public string Summary { get; set; }
}

Lalu kita buatkan model baru untuk target mapping kali ini. Kita namai WeatherRoom.

public class WeatherRoom
{
    public string Room { get; set; }
    public DateTime Date { get; set; }
    public int TemperatureC { get; set; }
    public int TemperatureR { get; set; }
    public string Summary { get; set; }
}

Setelah itu buatkan class baru AutoMapperProfile untuk membuat konfigurasi map sesuai kebutuhan.

public class AutoMapperProfile : Profile
{
    public AutoMapperProfile()
    {
        //map object WeatherForecast menjadi WeatherRoom
        CreateMap<WeatherForecast, WeatherRoom>();
    }
}

Kita pindah ke WeatherForecastController.cs dan tambahkan Dependency Injection di constructor.

private IMapper _mapper;

public WeatherForecastController(ILogger<WeatherForecastController> logger, IMapper mapper)
{
    _logger = logger;
    _mapper = mapper;
}

Lalu tambahkan Endpoint API baru untuk mengambil data WeatherRoom hasil dari mapping WeatherForecast.

[HttpGet("WeatherRoom")]
public IEnumerable<WeatherRoom> GetWeatherRoom()
{
    var rng = new Random();
    //populate data WeatherForecast dengan random number 
    var weatherForeCastEnum = Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateTime.Now.AddDays(index),
        TemperatureC = rng.Next(-20, 55),
        Summary = Summaries[rng.Next(Summaries.Length)]
    });
    //mapping data WeatherRoom dari WeatherForeCast
    var weatherRoom = _mapper.Map<IEnumerable<WeatherRoom>>(weatherForeCastEnum);
    return weatherRoom;
}

Setelah kita run, hasil dari weatherForeCastEnum adalah

[
  {
    "Date": "2020-07-05T10:11:48.6788616+07:00",
    "TemperatureC": -10,
    "TemperatureF": 15,
    "Summary": "Hot"
  },
  {
    "Date": "2020-07-06T10:11:48.7193388+07:00",
    "TemperatureC": -3,
    "TemperatureF": 27,
    "Summary": "Cool"
  },
  {
    "Date": "2020-07-07T10:11:48.7200952+07:00",
    "TemperatureC": 19,
    "TemperatureF": 66,
    "Summary": "Hot"
  },
  {
    "Date": "2020-07-08T10:11:48.7201173+07:00",
    "TemperatureC": -1,
    "TemperatureF": 31,
    "Summary": "Chilly"
  },
  {
    "Date": "2020-07-09T10:11:48.7201289+07:00",
    "TemperatureC": -13,
    "TemperatureF": 9,
    "Summary": "Balmy"
  }
]

Sedangkan hasil mapping ke WeatherRoom adalah

[
  {
    "room": null,
    "date": "2020-07-05T10:13:19.4494555+07:00",
    "temperatureC": 19,
    "temperatureR": 0,
    "summary": "Hot"
  },
  {
    "room": null,
    "date": "2020-07-06T10:13:19.4509221+07:00",
    "temperatureC": 53,
    "temperatureR": 0,
    "summary": "Balmy"
  },
  {
    "room": null,
    "date": "2020-07-07T10:13:19.4510079+07:00",
    "temperatureC": 25,
    "temperatureR": 0,
    "summary": "Warm"
  },
  {
    "room": null,
    "date": "2020-07-08T10:13:19.4510124+07:00",
    "temperatureC": 48,
    "temperatureR": 0,
    "summary": "Bracing"
  },
  {
    "room": null,
    "date": "2020-07-09T10:13:19.4510135+07:00",
    "temperatureC": 20,
    "temperatureR": 0,
    "summary": "Hot"
  }
]

Voilla, kita sudah berhasil melakukan mapping dari WeatherForecast ke WeatherRoom. Tapi, kita lihat ada beberapa properti yang valuenya masih default, apakah kita bisa mengatur properti tersebut otomatis?

Tentu bisa, kita bisa menggunakan fitur BeforeMap atau AfterMap. Apa itu?

BeforeMap adalah fungsi untuk merubah data dari input atau target sebelum melakukan mapping, sedangkan AfterMap adalah fungsi untuk merubah data dari input atau target setelah mapping. Hmm, kita coba saja biar lebih mudah memahaminya.

Kita ubah konfigurasi AutoMapper pada AutoMapperProfile seperti ini.

public AutoMapperProfile()
{
    //map object WeatherForecast menjadi WeatherRoom
    CreateMap<WeatherForecast, WeatherRoom>()
        .BeforeMap((f, r) => f.Summary = f.Summary + " asik")
        .AfterMap((f, r) => r.TemperatureR = Convert.ToInt32(f.TemperatureC * 0.45));
}

Pada fungsi BeforeMap, kita tambahkan teks “asik” pada summary, lalu pada AfterMap kita akan mengisi nilai dari TemperaturR dari hasil perhitungan TemperaturC  * 0.45.

Kita run sekali lagi hingga kita dapat hasil seperti ini.

weatherForeCastEnum

[
  {
    "Date": "2020-07-05T10:27:41.4824998+07:00",
    "TemperatureC": -17,
    "TemperatureF": 2,
    "Summary": "Chilly"
  },
  {
    "Date": "2020-07-06T10:27:41.5248275+07:00",
    "TemperatureC": 28,
    "TemperatureF": 82,
    "Summary": "Chilly"
  },
  {
    "Date": "2020-07-07T10:27:41.5255516+07:00",
    "TemperatureC": -19,
    "TemperatureF": -2,
    "Summary": "Chilly"
  },
  {
    "Date": "2020-07-08T10:27:41.5255696+07:00",
    "TemperatureC": -13,
    "TemperatureF": 9,
    "Summary": "Chilly"
  },
  {
    "Date": "2020-07-09T10:27:41.5255805+07:00",
    "TemperatureC": 47,
    "TemperatureF": 116,
    "Summary": "Mild"
  }
]

weatherRoom

[
  {
    "room": null,
    "date": "2020-07-05T10:28:09.5609512+07:00",
    "temperatureC": -6,
    "temperatureR": -3,
    "summary": "Mild asik"
  },
  {
    "room": null,
    "date": "2020-07-06T10:28:09.575253+07:00",
    "temperatureC": -11,
    "temperatureR": -5,
    "summary": "Warm asik"
  },
  {
    "room": null,
    "date": "2020-07-07T10:28:09.5752684+07:00",
    "temperatureC": 51,
    "temperatureR": 23,
    "summary": "Cool asik"
  },
  {
    "room": null,
    "date": "2020-07-08T10:28:09.575271+07:00",
    "temperatureC": 32,
    "temperatureR": 14,
    "summary": "Freezing asik"
  },
  {
    "room": null,
    "date": "2020-07-09T10:28:09.5752734+07:00",
    "temperatureC": 18,
    "temperatureR": 8,
    "summary": "Chilly asik"
  }
]

Kita sudah berhasil melakukan mapping beserta custom map datanya. Mudah bukan?

Semoga bermanfaat 😀

CategoriesProgramming

Menggunakan OData dengan ASP .Net Core API

OData Atau Open Data Protocol merupakan salah satu best practice untuk membangun atau menggunakan sebuah web api, OData sendiri dapat digunakan secara optional untuk membantu memanipulasi atau mengimplementasikan data secara khusus, kita dapat menggunakan query dalam protokol OData melalui endpointnya,  Odata dalam Asp .Net Sendiri dapat diakses secara optional misalkan data yang ada di web api endpoint default kita tidak akan diubah seluruhnya ke OData, sehingga data tersebut masih dapat diakses secara default. berikut merupakan langkah untuk konfigurasinya

Konfigurasi OData di ASP .Net Core 3.1

Pertama, Tambahkan “Microsoft.AspNetCore.OData” reference di NuGet Packages ke project kita

Buka file Startup.cs pada project kita,

Tambahkan “services.AddOData();” di dalam Method ConfigureServices untuk mengenalkan aplikasi kita tentang OData

 public void ConfigureServices(IServiceCollection services)
 {
     services.AddControllers();
     services.AddOData();
 }

jangan lupa untuk menambahkan reference pada file startup.cs juga

using Microsoft.AspNet.OData.Extensions;

Kemudian kita perlu menambahkan dependency Injection pada method Configure di file yang sama pada UseMvcnya, dan juga tambahkan funsi query -query yang akan kita gunakan untuk memanipulasi data kita nantinya.

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseHttpsRedirection();
            app.UseRouting();
            app.UseMvc(routeBuilder =>
            {
                routeBuilder.EnableDependencyInjection();
                routeBuilder.Expand().Select().Filter().Count().OrderBy();
            });
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

Hal yg perlu dilakukan selanjutnya adalah membuat route untuk mengakses ke format ODatanya sendiri sehingga data dalam endpoint kita masih bisa di akses dalam format default.

Buat method baru pada file startup.cs untuk menentukan Entity data model untuk ODatanya

IEdmModel GetEdmModel()
 {
     var odataBuilder = new ODataConventionModelBuilder();
     odataBuilder.EntitySet<BDFEntitlement>("IniPegawai");

return odataBuilder.GetEdmModel();
}

Tambahkan reference pada file startup.cs

using Microsoft.OData.Edm;
using Microsoft.AspNet.OData.Builder;

nb: dalam code diatas “BDFEntitlement” adalah model yang akan menjadi format result dari data kita, “IniPegawai” adalah web api controller kita. jadi kita dapat menambahkan Entityset seperlu kita.

Kemudian Kembali ke Method Configure untuk comment fungsi UseEndpointsnya karena kita akan menggunakan route dari ODatanya.

sama seperti alasan diatas, pada UseMvc kita perlu menambahkan

routeBuilder.MapODataServiceRoute("odata", "odata", GetEdmModel());

Kemudian karena kita menggunakan mvc di sini perlu untuk mendisable EndpointRoutingnya di method ConfigureServices pada service “AddController”, Rubah seperti dibawah ini.

services.AddControllers(mvcOptions => mvcOptions.EnableEndpointRouting = false);

Dengan ini konfigurasi di file startup.cs sudah selesai, dan dapat dilanjutkan ke webapi controllernya

langkah terakhir, hanya perlu menambahkan configurasi di setiap atas method controller yang akan kita gunakan dengan bersama OData seperti

// GET: api/IniPegawai
  [HttpGet]
  [EnableQuery()]
  public IEnumerable Get()
  {
      return _context.BDFEntitlement.AsNoTracking().ToList();
  }

Tambah reference pada controller Anda

using Microsoft.AspNet.OData;


Implementasi sederhana menggunakan OData

1. tanpa OData dengan endpoint

https://localhost:44383/api/inipegawai

2. Dengan OData dan mencoba querying pada endpoint nya

https://localhost:44383/odata/inipegawai?$Select=ProgramName,Remark,id&$filter=ProgramName eq 'Program Algostudio A'


Konklusi :

OData bisa berguna untuk membantu kita memanipulasi data sesuai yang kita butuhkan tanpa harus membuat endpoint lain, selain itu banyak query-query OData yang berguna misalkan expand yang memiliki fungsi untuk dapat menggabungkan lebih dari 1 data di endpoint berbeda dan banyak lainnya. mudahnya memanipulasi di data dari resultnya ini yang menurut Saya menjadikan Entity Framework yang menggunakan OData lebih fleksibel dari Entity Framework yang tidak menggunakan OData, untuk pembahasan lebih perbandingannya mungkin akan ada di artikel selanjutnya.

Terima kasih & Semoga artikel ini bermanfaat.

CategoriesProgramming

Menambah IdentityUser Property di Identity ASP.Net Core

Identity pada ASP.Net Core ada untuk memudahkan kita menambahkan user dan mengatur user management pada website. Bahkan Identity sudah bisa menghandle  TwoFactorAuthentication, ExternalLogins dll. Secara default, identity akan membuat user dengan bentuk model seperti berikut.

Bisa kita lihat IdentityUser hanya terdiri dari beberapa property dan tidak bisa kita ubah. Lalu bagaimana jika kita butuh untuk menambah property?

Misalnya kita akan menambah property “Address” pada user, berikut langkahnya

Buat Model Baru

Mari kita buat Model baru yang extend pada IdentityUser

using Microsoft.AspNetCore.Identity;
namespace CustomIdentityUser.Models
{
    public class ApplicationUser: IdentityUser
    {
        public string Address { get; set; }
    }
}

Update Database Context

Ubah extend DatabaseContext menjadi “IdentityDbContext<ApplicationUser>”. Sehingga menjadi seperti ini

namespace CustomIdentityUser.Data
{
    public class ApplicationDbContext : IdentityDbContext
    {
        public ApplicationDbContext(DbContextOptions options)
            : base(options)
        {
        }
    }
}

Update Startup

Ubah configurasi Identity dari IdentityUser

services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true)
                .AddEntityFrameworkStores();

Menjadi ApplicationUser

services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true)
                .AddEntityFrameworkStores();

Update Views/Shared/_LoginPartial.cshtml

Ubah kode berikut

@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

Menjadi

@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager

Add Default Identity Pages

  1. Klik kanan pada project
  2. Pilih Add > New Scaffolded Item
  3. Pilih Identity dan tekan Add
  4. Kamu bisa pilih override all files, atau hanya pilih beberapa yang kamu butuhkan. Misal saat ini kita pilih Account/Register
  5. Pilih database context yang sudah tersedia

Langkah ini akan membuat page register secara otomatis.

Register.cshtml.cs

Tambahkan property Address pada InputModel

public string Address { get; set; }

Tambahkan Address pada ApplicationUser di OnPostAsync

var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email, Address = Input.Address };

Register.cshtml

Tambahkan input untuk address pada form

<div class="form-group">
    <label asp-for="Input.Address"></label>
    <input asp-for="Input.Address" class="form-control" />
    <span asp-validation-for="Input.Address" class="text-danger"></span>
</div>

Add Migration dan Update Database

Tambahkan migrasi dengan command berikut pada Package Manager Console

add-migration AddCustomUser

Lalu update database dengan command

update-database

Jalankan website dan coba lakukan register

Dan saat kita buka di database, bisa dilihat sudah muncul Addres pada table AspNetUsers