﻿
{"id":26770,"date":"2023-12-06T19:38:36","date_gmt":"2023-12-06T19:38:36","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=26770"},"modified":"2023-12-06T19:38:36","modified_gmt":"2023-12-06T19:38:36","slug":"net-8-minimal-apilar-da-form-binding-islemi","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/net-8-minimal-apilar-da-form-binding-islemi\/","title":{"rendered":".NET 8 &#8211; Minimal API&#8217;lar da Form Binding \u0130\u015flemi"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>Bu i\u00e7eri\u011fimizde .NET 8 ile Asp.NET Core mimarisinde minimal api&#8217;ler de form binding&#8217;e y\u00f6nelik gelen yenili\u011fe dair odaklanacak ve bu destekle birlikte form kullan\u0131m\u0131 a\u00e7\u0131s\u0131ndan MVC controller&#8217;lar\u0131na olan ba\u011f\u0131ml\u0131l\u0131\u011f\u0131n ortadan kald\u0131r\u0131lmas\u0131 temellerinin nas\u0131l at\u0131ld\u0131\u011f\u0131n\u0131 inceliyor olaca\u011f\u0131z.<\/p>\n<p>Malumunuz, minimal api&#8217;ler HTML ile \u00e7al\u0131\u015fmak i\u00e7in herhangi bir olanak sa\u011flamamakta ve odak noktas\u0131 olarak JSON t\u00fcr\u00fcnden verileri \u00fcretmek ve t\u00fcketmek \u00fczerine kurgulanmaktad\u0131r. Tabi bu \u015fartlarda minimal api&#8217;ler de illa HTML i\u00e7erikleri olu\u015fturmak istiyor yahut b\u00f6yle bir ihtiya\u00e7 do\u011frultusunda hareket etmeniz gerekiyorsa i\u015fte bu taktirde a\u015fa\u011f\u0131daki gibi bir string tan\u0131mlamas\u0131yla ihtiyac\u0131n\u0131z\u0131 giderebilirsiniz.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nusing System.Net.Mime;\r\n\r\nvar builder = WebApplication.CreateBuilder(args);\r\n\r\nvar app = builder.Build();\r\n\r\napp.MapGet(&quot;\/&quot;, () =&gt;\r\n{\r\n    string html = &quot;&quot;&quot;\r\n                  &lt;!DOCTYPE html&gt;\r\n                  &lt;html&gt;\r\n                      &lt;head&gt;\r\n                        &lt;title&gt;Page Title&lt;\/title&gt;\r\n                      &lt;\/head&gt;\r\n                  &lt;body&gt;\r\n                      &lt;h1&gt;This is a Heading&lt;\/h1&gt;\r\n                      &lt;p&gt;This is a paragraph.&lt;\/p&gt;\r\n                  &lt;\/body&gt;\r\n                  &lt;\/html&gt;\r\n                  &quot;&quot;&quot;;\r\n\r\n    return Results.Content(html, MediaTypeNames.Text.Html);\r\n});\r\n\r\napp.Run();\r\n\r\n<\/pre>\n<\/div>\n<p>Amma velakin gelin g\u00f6r\u00fcn ki, minimal api&#8217;ler de POST edilmi\u015f olan form verilerini yakalamak(bind olmak) .NET 7 ve \u00f6ncesinde pek m\u00fcmk\u00fcn de\u011fildir. Evet, post edilmi\u015f olan form verilerini Razor Page ve controller&#8217;lar da rahatl\u0131kla kullanabilirken, minimal api&#8217;ler de kullanam\u0131yorduk. Tabi form&#8217;lardan gelecek olan <code>multipart\/form-data<\/code> i\u00e7erik t\u00fcr\u00fcnden olan verileri <code>IFormFile<\/code> referans\u0131yla bind edebiliyor ve hatta <code>IFormFileCollection<\/code> referans\u0131yla da \u00e7o\u011ful olarak kar\u015f\u0131layabiliyorduk. Yani form binding yap\u0131lanmas\u0131 minimal api&#8217;ler a\u00e7\u0131s\u0131ndan k\u0131smen ge\u00e7erlilik g\u00f6steriyordu.<\/p>\n<p>Bunu hemen \u00f6rneklendirmemiz gerekirse e\u011fer;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nusing Microsoft.AspNetCore.Antiforgery;\r\nusing Microsoft.AspNetCore.Mvc;\r\nusing System.Net.Mime;\r\n\r\nvar builder = WebApplication.CreateBuilder(args);\r\nbuilder.Services.AddAntiforgery();\r\n\r\nvar app = builder.Build();\r\napp.UseAntiforgery();\r\n\r\napp.MapGet(&quot;\/&quot;, (IAntiforgery antiforgery, HttpContext context) =&gt;\r\n{\r\n    var token = antiforgery.GetAndStoreTokens(context);\r\n    string html = $&quot;&quot;&quot;\r\n                      &lt;form action=&quot;\/upload-file&quot; method=&quot;post&quot; enctype=&quot;multipart\/form-data&quot;&gt;\r\n                          &lt;input name=&quot;{token.FormFieldName}&quot; type=&quot;hidden&quot; value=&quot;{token.RequestToken}&quot; \/&gt;\r\n                          &lt;input type=&quot;file&quot; name=&quot;file&quot;&gt;\r\n                          &lt;input type=&quot;submit&quot; value=&quot;G\u00f6nder&quot;&gt;\r\n                      &lt;\/form&gt;\r\n                  &quot;&quot;&quot;;\r\n\r\n    return Results.Content(html, MediaTypeNames.Text.Html, Encoding.UTF8);\r\n});\r\n\r\napp.MapPost(&quot;\/upload-file&quot;, async (&#x5B;FromForm] IFormFile file) =&gt;\r\n{\r\n    return TypedResults.Ok(file);\r\n});\r\n\r\napp.Run();\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki kod blo\u011funu incelerseniz e\u011fer <strong><em>11<\/em><\/strong> ile <strong><em>23.<\/em><\/strong> sat\u0131r aral\u0131\u011f\u0131nda form yap\u0131s\u0131 olu\u015fturulurken bir yandan da <a href=\"https:\/\/www.gencayyildiz.com\/blog\/asp-net-mvcde-csrfxsrfcross-site-request-forgery-saldiri-guvenligi\/\" rel=\"noopener\" target=\"_blank\">CSRF\/XSRF(Cross-Site Request Forgery)<\/a> sald\u0131r\u0131lar\u0131na kar\u015f\u0131 Anti-forgery \u00f6nlemi al\u0131nmaktad\u0131r. Bunun nedeni form submit edildi\u011finde bunu kar\u015f\u0131layacak olan &#8216;upload-file&#8217; endpoint&#8217;inin bu olas\u0131 sald\u0131r\u0131lardan korunmas\u0131 i\u00e7in Asp.NET Core mimarisi taraf\u0131ndan al\u0131nan varsay\u0131lan bir koruma mekanizmas\u0131d\u0131r. Dolay\u0131s\u0131yla burada Anti-forgery \u00f6nlemi i\u00e7in <strong><em>6.<\/em><\/strong> sat\u0131rda <code>AddAntiforgery<\/code> servisi eklenmekte ve <strong><em>9.<\/em><\/strong> sat\u0131rda da endpoint&#8217;lere gelen isteklerde anti-forgery koruma kontrol\u00fcn\u00fcn yap\u0131labilmesi i\u00e7in <code>UseAntiforgery<\/code> middleware&#8217;i \u00e7a\u011fr\u0131lmaktad\u0131r. Ard\u0131ndan yine <strong><em>11<\/em><\/strong> ile <strong><em>23.<\/em><\/strong> sat\u0131r aral\u0131\u011f\u0131nda <code>IAntiforgery<\/code> aray\u00fcz\u00fcne kar\u015f\u0131l\u0131k instance IoC Container&#8217;dan dependency injection ile talep edilmekte ve gerekli g\u00fcvenlik token&#8217;\u0131 olu\u015fturulup form i\u00e7erisindeki <strong><em>16.<\/em><\/strong> sat\u0131rdaki &#8216;hidden&#8217; input&#8217;una verilmektedir. Tabi burada <code>token.FormFieldName<\/code> komutu neticesinde <em>&#8216;__RequestVerificationToken&#8217;<\/em> de\u011ferinin gelece\u011fini bilmenizde fayda vard\u0131r.<\/p>\n<blockquote><p><em><br \/>\nAsp.NET Core mimarisinde varsay\u0131lan olarak aktif gelen Anti-forgery \u00f6nlemini kald\u0131rmak istiyorsan\u0131z a\u015fa\u011f\u0131daki gibi <code>DisableAntiforgery()<\/code> metodunu kullanabilirsiniz.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\napp.MapPost(&quot;\/upload-file&quot;, async (&#x5B;FromForm] IFormFile file) =&gt;\r\n{\r\n    return TypedResults.Ok(file);\r\n}).DisableAntiforgery();\r\n<\/pre>\n<\/div>\n<p><\/em><\/p><\/blockquote>\n<p>Velhas\u0131l kelam, yap\u0131lan t\u00fcm bu \u00e7al\u0131\u015fmalar neticesinde taray\u0131c\u0131 \u00fczerinden form&#8217;u submit etti\u011fimizde dosya bilgileri &#8216;upload-file&#8217; endpoint&#8217;inde elde edilecektir.<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2023\/12\/NET-8-Minimal-APIlar-da-Form-Binding-Islemi.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2023\/12\/NET-8-Minimal-APIlar-da-Form-Binding-Islemi.gif\" alt=\".NET 8 - Minimal API&#039;lar da Form Binding \u0130\u015flemi\" width=\"672\" height=\"322\" class=\"aligncenter size-full wp-image-26773\" \/><\/a>\u015eimdi bu \u00e7al\u0131\u015fma \u00fczerine a\u015fa\u011f\u0131daki gibi bir form&#8217;un da post edilmesinde herhangi bir sak\u0131nca g\u00f6r\u00fclmemektedir, \u00f6yle de\u011fil mi?<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n&lt;form action=&quot;\/upload-file&quot; method=&quot;post&quot; enctype=&quot;multipart\/form-data&quot;&gt;\r\n    &lt;input name=&quot;{token.FormFieldName}&quot; type=&quot;hidden&quot; value=&quot;{token.RequestToken}&quot; \/&gt;\r\n    &lt;input type=&quot;file&quot; name=&quot;file&quot;&gt;\r\n    &lt;input type=&quot;text&quot; name=&quot;fileName&quot;&gt;\r\n    &lt;input type=&quot;text&quot; name=&quot;description&quot;&gt;\r\n    &lt;input type=&quot;submit&quot; value=&quot;G\u00f6nder&quot;&gt;\r\n&lt;\/form&gt;\r\n<\/pre>\n<\/div>\n<p>Bu formdaki file d\u0131\u015f\u0131nda kalan ekstra verileri .NET 8 \u00f6ncesinde a\u015fa\u011f\u0131daki gibi elde edebiliyorduk;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\napp.MapPost(&quot;\/upload-file&quot;, async (&#x5B;FromForm] IFormFile file, HttpRequest request) =&gt;\r\n{\r\n    IFormCollection formCollection = await request.ReadFormAsync();\r\n    var fileName = formCollection&#x5B;&quot;fileName&quot;];\r\n    var description = formCollection&#x5B;&quot;description&quot;];\r\n    return TypedResults.Ok(file);\r\n});\r\n<\/pre>\n<\/div>\n<p>.NET 8 ile ise \u015f\u00f6yle elde edebiliyoruz;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\napp.MapPost(&quot;\/upload-file&quot;, async (&#x5B;FromForm] IFormFile file, &#x5B;FromForm] string fileName, &#x5B;FromForm] string description) =&gt;\r\n{\r\n    return TypedResults.Ok(file);\r\n});\r\n<\/pre>\n<\/div>\n<p>ya da a\u015fa\u011f\u0131daki gibi complex type olarak da kar\u015f\u0131layabiliyoruz;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\napp.MapPost(&quot;\/upload-file&quot;, async (&#x5B;FromForm] UploadFileInfo model) =&gt;\r\n{\r\n    return TypedResults.Ok(model);\r\n});\r\n<\/pre>\n<\/div>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class UploadFileInfo\r\n    {\r\n        public IFormFile File { get; set; }\r\n        public string FileName { get; set; }\r\n        public string Description { get; set; }\r\n    }\r\n<\/pre>\n<\/div>\n<blockquote><p><em>.NET 8&#8217;den itibaren, <code>IFormFile<\/code> ve <code>IFormFileCollection<\/code> referanslar\u0131nda <code>[FromForm]<\/code> attribute&#8217;unu uygulaman\u0131za gerek yoktur!<\/em><\/p><\/blockquote>\n<p>Nihai olarak,<br \/>\n.NET 8&#8217;de minimal api&#8217;ler i\u00e7in HTML form yap\u0131lanmalar\u0131na kar\u015f\u0131n binding mekanizmas\u0131n\u0131n \u015fekillendi\u011fini ve bunlar\u0131n d\u0131\u015f\u0131nda Anti-forgery \u00f6nlemine kar\u015f\u0131n gerekli \u00e7al\u0131\u015fmalar\u0131n nas\u0131l yap\u0131labilece\u011fini incelemi\u015f olduk.<\/p>\n<p>\u0130lgilenenlerin faydalanmas\u0131 dile\u011fiyle&#8230;<br \/>\nSonraki yaz\u0131lar\u0131mda g\u00f6r\u00fc\u015fmek \u00fczere&#8230;<br \/>\n\u0130yi \u00e7al\u0131\u015fmalar&#8230;<\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>Merhaba, Bu i\u00e7eri\u011fimizde .NET 8 ile Asp.NET Core mimarisinde minimal api&#8217;ler de form binding&#8217;e y\u00f6nelik gelen yenili\u011fe dair odaklanacak ve bu destekle birlikte form kullan\u0131m\u0131 a\u00e7\u0131s\u0131ndan MVC controller&#8217;lar\u0131na olan ba\u011f\u0131ml\u0131l\u0131\u011f\u0131n ortadan kald\u0131r\u0131lmas\u0131 temellerinin nas\u0131l&#46;&#46;&#46;<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":26539,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4912],"tags":[4915,4982,4930,4983],"class_list":["post-26770","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-8","tag-net-8","tag-form-binding","tag-minimal-api","tag-minimal-api-form-binding"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/26770","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/comments?post=26770"}],"version-history":[{"count":3,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/26770\/revisions"}],"predecessor-version":[{"id":26774,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/26770\/revisions\/26774"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/26539"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=26770"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=26770"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=26770"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}