GraphQL In .NET Core Web API With Entity Framework Core


관련 자료

https://www.c-sharpcorner.com/article/graphql-in-net-core-web-api-with-entity-framework-core-part-one/

 

GraphQL In .NET Core Web API With Entity Framework Core - Part One

In this article, we will see how GraphQL works with Entity Framework Core and is exposed through Web API in .NET Core.

www.c-sharpcorner.com

https://fullstackmark.com/post/17/building-a-graphql-api-with-aspnet-core-2-and-entity-framework-core

 

Building a GraphQL API with ASP.NET Core 2 and Entity Framework Core

GraphQL is a relatively new technology developed initially at Facebook and open-sourced to the world in 2015. In 2017, it really took off and made the leap from a cool, niche technology to one of the primary ways companies like Walmart and IBM are starting

fullstackmark.com

https://medium.com/shemseddine-on-code/setup-a-graphql-api-using-asp-net-core-79f1b88f6ad8

 

Setup a GraphQL API using ASP.NET Core

A short guide on how to setup your own GraphQL API using ASP .NET Core

medium.com

https://medium.com/volosoft/building-graphql-apis-with-asp-net-core-419b32a5305b

 

Building GraphQL APIs with ASP.NET Core

Building and consuming GraphQL in your .NET application

medium.com

https://docs.microsoft.com/ko-kr/aspnet/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/create-an-odata-v4-endpoint

 

ASP.NET Web API 2.2 사용 하 여 OData v4 엔드포인트 만들기

Open Data Protocol (OData)는 웹에 대 한 데이터 액세스 프로토콜. OData 쿼리 및 CRUD 작업을 통해 데이터 집합을 조작할 일관 된 방식으로 제공 하는 중...

docs.microsoft.com

https://medium.com/@FourwingsY/graphql%EC%9D%84-%EC%98%A4%ED%95%B4%ED%95%98%EB%8B%A4-3216f404134

 

 

GraphQL을 오해하다

이번엔 GraphQL을 처음 접한 순간부터, 토이 프로젝트(서버)를 만드는 동안 내가 겪었던 착오와 오해, 햇갈렸던 개념들을 복습해보고자 한다. GraphQL이 대체 뭔가 하는 질문에 대해서는 다른 글을 보길 바란다. GraphQL을 전혀 모르는…

medium.com

https://velopert.com/2318

 

GraphQL 강좌 1편: GraphQL이 무엇인가? | VELOPERT.LOG

최근 페이스북에서 만든 어플리케이션 레이어 쿼리 언어인 GraphQL 이 공식릴리즈되어 여기저기서 적용한 사례가 생기고있죠 (페이스북은 원래부터 사용하고있었고, 대표적으로 갓 GitHub..) 이 GraphQL 이 뭔지, 이게 왜 필요한건지, 기존의 방식과 뭐가 달라지는건지, 한번 갈피를 잡아봅시다. GraphQL 강좌 1편: GraphQL이 무엇인가? 소개 GraphQL 은 페이스북에서 만든 어플리케이션 레이어 쿼리 언어입니다. 기존의 웹 혹은 모바일

velopert.com

 

 



 

 위키백과에서는 다음과 같이 설명하고 있다.

 GraphQL은 페이스북이 2012년에 개발하여 2015년에 공개적으로 발표된 데이터 질의어이다. 그래프QL은 REST 및 부속 웹서비스 아키텍쳐를 대체할 수 있다. 클라이언트는 필요한 데이터의 구조를 지정할 수 있으며, 서버는 정확히 동일한 구조로 데이터를 반환한다. 

 쉽게 풀이하면 하나의 앤드포인트에서 내가 원하는 스키마(데이터 컬럼 양)로 데이터를 가져올 수 있다. Web API로 개발하면 클라이언트에서 사용하지 않는 데이터가 포함되어 내려갈 수 있지만, GraphQL에서는 필요한 데이터만 요청하고 사용하기 때문에 서버 리소스나, 네트워크 리소스를 절약할 수 있게 되고, 무엇보다 장점이 데이터의 종류에 맞게 대응되는 컨트롤러를 만들 필요 없이 하나의 주소에서 호출하여 사용할 수 있도록 할 수 있다.

 

 

[그림1] GraphQL 개념도

 

Dynamic Role-Based Authorization in ASP.NET Core 2.0


관련 자료

 

 

Dynamic Role-Based Authorization in ASP.NET Core 2.0

You already know how role-based authorization works in ASP.NET Core but what if you don't want hardcode roles in authorization attribute or create roles later and specify in which controller and action it has access without touching source code?

www.codeproject.com

 

 

mo-esmp/DynamicRoleBasedAuthorizationNETCore

Dynamic Role-Based Authorization in ASP.NET Core 2.0 - mo-esmp/DynamicRoleBasedAuthorizationNETCore

github.com



 

You already know how role-based authorization works in ASP.NET Core but what if you don't want hardcode roles in authorization attribute or create roles later and specify in which controller and action it has access without touching source code?

Introduction

You already know how role-based authorization works in ASP.NET Core.

Hide   Copy Code

[Authorize(Roles = "Administrator")] public class SomeController : Controller { }

But what if you don't want hardcode roles in authorization attribute or create roles later and specify in which controller and action it has access without touching source code?

Using the Code

Let's begin our journey. Create ASP.NET Core Web Application project and change authentication to Individual User Accounts.

 

 

ASP.NET 5 MVC6에서 Glimpse 사용하기


참조 URL
  1. http://blog.getglimpse.com/2015/11/19/installing-glimpse-v2-beta1/

 


우선 MVC6 프로젝트를 두가지로 나눠서 테스트를 해보도록 하겠다. .Net Core와 .Fremework로 각각의 프로젝트로 만들고 아래와 같이 NuGet에서 Glimpse를 includ prerelease를 체크하고 검색하면 아래와 같이 "v2.0.0-beta1" 버전이 검색이 되며 각각의 프로젝트에 추가를 한다.


[그림1] NuGet에서 검색된 결과 화면




[그림2] Glimpse를 추가한 프로젝트


Glimpse는 현재 버전에서는 에러가 나고 있는 걸로 봐서 "Core" 버전을 지원하지 않고 있는 것으로 파악이 되며 .Net Framework로 만들어진 MVC6 프로젝트는 정상적으로 표시가 되고 있다. 차후에는 "Core"버전도 지원이 되었으면 하는 바램이다.




[그림3] .Net Framework의 project.json 파일에 "Glimpse" 추가




 .Net Core에서는 지원하지 않는 것으로 확인이 되었으니 이제 MVC6 .Net Framework를 확인해 보도록 한다.



[그림4] .Net Framework 에서 app.UseGlimpse() 에러


위와 같이 Glimpse를 추가한 상태에서 "services.AddGlimpse();" 까지 적용하고 "Configue" 메소드에서 "app.UseGlimpse()"를 입력하면 에러가 발생이 되고 있다. 가이드 대로 똑같이 진행 하였으나 에러가 발생이 되는 이유를 분석하여 보니 Glimpse beta1은 2015년 11월달에 나왔고, MVC6는 현재 2016년 7월에 update3를 통해 계속 패치가 되던중에 namespace가 변경이 된것으로 추정이 된다. 그래서 네임스페이스가 상이하여 "UseGlimpse()"를 사용할 수 없게 된것이다. 이건 다음 beta가 나오면 해결 될 것으로 보여지는 현재 버전에서는 사용할 수 없다. 


 지금까지 MVC6에서 Glimpse beta1에 대해서 알아 보았으나 현재 버전에서는 사용할 수 없는 것으로 확인이 되었다. 어서 빨리 다음 버전이 나와서 사용할 수 있었으면 하는 바램이다.


















ASP.NET 5 & MVC 6 관련 링크


참조 URL
  1. https://www.youtube.com/watch?v=4EGDxkWoUOY
  2. http://www.asp.net/
  3. https://docs.asp.net
  4. https://docs.asp.net/en/latest/tutorials/first-mvc-app/start-mvc.html
  5. https://docs.asp.net/en/latest/tutorials/first-web-api.html

 

 ASP.NET 5와 MVC 6 에서는 .Net Core를 이용하여 통합하였다. 이전까지는 필터나 어트리뷰트를 각자 만들어서 사용하는 불편함이 있었지만 이번 통합으로 인해 한번의 개발로 같이 사용할 수 있도록 되었다. 그 밑바탕에는 .Net Core를 사용하였으며 이로인해 IIS와는 별개로 자연스레 크로스플랫폼(Windows, Linux, OSX)에서 서비스를 할 수 있는 길이 열렸다.











브라우저에서 NTLM으로 로그인 하기


참조 URL
  1. https://github.com/erlandranvinge/ntlm.js
  2. https://github.com/erlandranvinge/ntlm.js/blob/master/ntlm.js

 



NTLM.js 라이브러리의 핵심은 UserName과 Password를 Base64로 인코딩하여 헤더에 추가하여 보내는 로직이다. 

ntlm.js 파일의 "Msg.prototype.toBase64 = function()" 통해서 인코딩하는 로직으로 확인할 수 있으며 "setCredentials"와 "authenticate"를 통해서 사용하면 된다.


Usage

Ntlm.setCredentials('domain', 'username', 'password');
var url = 'http://myserver.com/secret.txt';

if (Ntlm.authenticate(url)) {
    var request = new XMLHttpRequest();
    request.open('GET', url, false);
    request.send(null);
    console.log(request.responseText);
    // => My super secret message stored on server.
}

Setup

On the server side, the following CORS HTTP Response headers are required:

  • Access-Control-Allow-Headers: Authorization
  • Access-Control-Allow-Methods: GET, OPTIONS
  • Access-Control-Allow-Origin: *
  • Access-Control-Expose-Headers: WWW-Authenticate





























NHibernate and ASP.NET MVC - CRUD Operations


참조 URL
  1. http://www.dotnetjalps.com/2013/09/asp-net-mvc-nhibernate-crud-getting-started.html
  2. http://www.dotnetjalps.com/2014/07/fluent-nhibernate-asp-net-mvc-crud.html

 


이 문서에 대하여

이 문서는 원본 문서를 읽고, 따라하고, 변경 또는 수정없이 인용한 부분이 있으며 주석이나 추가 설명에 대해 가감을 하였습니다. 이 문서와는 별개로 별도의 원본이 있음을 알려 드리며 원본에 대한 자세한 사항은 참조 URL에 있음을 알려 드립니다. 오역, 어색한 부분, 매끄럽지 않은 부분이 있을 경우 알려주시면 적극적으로 반영하도록 하겠습니다.





   실습 준비 사항


  • Visual Studio 2013
  • ASP.NET MVC5
  • LocalDB 11 




 NHibernate를 통해 ASP.NET MVC에서 간단한 CRUD를 해보도록 하겠다. 우선 준비 사항으로 데이터 베이스가 필요하여 아래와 같이 Employee테이블을 만들었다. '코드1'에서 관련 Query가 있으니 SQL Server Management Studio에서 실행하여 테이블을 생성할 수 있도록 하였다.



[그림1] Employee Table




CREATE TABLE [dbo].[Employee](
	[Id] [intIDENTITY(1,1NOT NULL,
	[FirstName] [nvarchar](50NULL,
	[LastName] [nvarchar](50NULL,
	[Designation] [nvarchar](50NULLON [PRIMARY]

[코드1] Create query Employee table 





 이제 준비가 되었으면 아래와 같이 웹 프로젝트를 만들어 보자.



[그림2] ASP.NET MVC template




[그림3] ASP.NET MVC Web API 선택



NHibernate 관련 DLL을 참조 하여야 한다. 참조 방법은 PM( Tools -> NuGet Package Manager -> Package Manager Console )에서 "Install-Package NHibernate"를 입력하면 참조가 된다.
( "그림4"에서는 이미 참조가 되어 있는 관계로 처음 참조하는 화면과는 다르며 예시를 하기 위함입니다. )




[그림4] Package Manager Console




NHibernate에서 사용하는 Config 파일을 Models폴더에 추가 하자. 추가할 파일명은 "Hibernate.cfg.xml"로 한다.


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="connection.provider">
      NHibernate.Connection.DriverConnectionProvider
    </property>
    <property name="connection.driver_class">
      NHibernate.Driver.SqlClientDriver
    </property>
    <property name="connection.connection_string">
      Server=(LocalDB)\v11.0;Integrated Security=true;AttachDbFileName=C:\Users\천호\NHibernateTest.mdf
    </property>
    <property name="dialect">
      NHibernate.Dialect.MsSql2012Dialect
    </property>
  </session-factory>
</hibernate-configuration>

[코드2] NHibernate.cfg.xml



이제 Employee 관련 모델 클래스를 만든다.


public class Employee
{
    public virtual int Id { getset; }
    public virtual string FirstName { getset; }
    public virtual string LastName { getset; }
    public virtual string Designation { getset; }
}

[코드3] Employee model class



이제 모델 클래스와 DB의 Table과 매칭시켜 주는 파일을 Models 폴더에 추가해야 한다. 파일명은 "Employee.hbm.xml"로 한다.


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true" assembly="NHibernateTest" namespace="NHibernateTest.Models">
  <class name="Employee" table="Employee" dynamic-update="true" >
    <cache usage="read-write"/>
    <id name="Id" column="Id" type="int">
      <generator class="native" />
    </id>
    <property name="FirstName" />
    <property name="LastName" />
    <property name="Designation" />
  </class>
</hibernate-mapping>

[코드4] Employee.hbm.xml




NHibernate을 접근하기 위한 Helper 클래스를 만든다.


public static ISession OpenSession()
{
    var configuration = new Configuration();
    // Configue 파일에 대한 정보
    var configurationPath = HttpContext.Current.Server.MapPath(@"~\Models\hibernate.cfg.xml");
    configuration.Configure(configurationPath);
 
    // 매칭 정보에 관한 파일
    var employeeConfigurationFile = HttpContext.Current.Server.MapPath(@"~\Models\Employee.hbm.xml");
            
    configuration.AddFile(employeeConfigurationFile);
    ISessionFactory sessionFactory = configuration.BuildSessionFactory();
    return sessionFactory.OpenSession();
}

[코드5] NHibernateSession Helper 클래스


 위 코드에서 MapPath를 통해 설정 정보와 매칭 정보가 있는 파일 정보를 세션 객체를 초기화 하는 작업이다. 이제 기본적인 준비 작업은 마무리가 되었으며 Controller에서 CRUD를 해보도록 하겠다.



public ActionResult Index()
{
	using (ISession session = NHibertnateSession.OpenSession())
	{
		var employees = session.Query<Employee>().ToList();
		return View(employees);
	}
}
 
public ActionResult Create()
{
	return View();
}
 
 
[HttpPost]
public ActionResult Create(Employee emplolyee)
{
	try
	{
		using (ISession session = NHibertnateSession.OpenSession())
		{
			using (ITransaction transaction = session.BeginTransaction())
			{
				session.Save(emplolyee);
				transaction.Commit();
			}
		}
 
		return RedirectToAction("Index");
	}
	catch (Exception exception)
	{
		return View();
	}
}
 
public ActionResult Edit(int id)
{
	using (ISession session = NHibertnateSession.OpenSession())
	{
		var employee = session.Get<Employee>(id);
		return View(employee);
	}
 
}
 
 
[HttpPost]
public ActionResult Edit(int idEmployee employee)
{
	try
	{
		using (ISession session = NHibertnateSession.OpenSession())
		{
			var employeetoUpdate = session.Get<Employee>(id);
 
			employeetoUpdate.Designation = employee.Designation;
			employeetoUpdate.FirstName = employee.FirstName;
			employeetoUpdate.LastName = employee.LastName;
 
			using (ITransaction transaction = session.BeginTransaction())
			{
				session.Save(employeetoUpdate);
				transaction.Commit();
			}
		}
		return RedirectToAction("Index");
	}
	catch
	{
		return View();
	}
}
 
public ActionResult Details(int id)
{
	using (ISession session = NHibertnateSession.OpenSession())
	{
		var employee = session.Get<Employee>(id);
		return View(employee);
	}
}
 
public ActionResult Delete(int id)
{
	using (ISession session = NHibertnateSession.OpenSession())
	{
		var employee = session.Get<Employee>(id);
		return View(employee);
	}
}
 
 
[HttpPost]
public ActionResult Delete(int idEmployee employee)
{
	try
	{
		using (ISession session = NHibertnateSession.OpenSession())
		{
			using (ITransaction transaction = session.BeginTransaction())
			{
				session.Delete(employee);
				transaction.Commit();
			}
		}
		return RedirectToAction("Index");
	}
	catch (Exception exception)
	{
		return View();
	}
}

[코드6] EmployeeController




이제 View 페이지를 만든다.


@model NHibernateTest.Models.Employee
 
@{
    ViewBag.Title = "Create";
}
 
<h2>Create</h2>
 
 
@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>Employee</h4>
        <hr />
        @Html.ValidationSummary(true)
 
        <div class="form-group">
            @Html.LabelFor(model => model.FirstNamenew { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.FirstName)
                @Html.ValidationMessageFor(model => model.FirstName)
            </div>
        </div>
 
        <div class="form-group">
            @Html.LabelFor(model => model.LastNamenew { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.LastName)
                @Html.ValidationMessageFor(model => model.LastName)
            </div>
        </div>
 
        <div class="form-group">
            @Html.LabelFor(model => model.Designationnew { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Designation)
                @Html.ValidationMessageFor(model => model.Designation)
            </div>
        </div>
 
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}
 
<div>
    @Html.ActionLink("Back to List""Index")
</div>
 
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

[코드7] Create




@model IEnumerable<NHibernateTest.Models.Employee>
 
@{
    ViewBag.Title = "Index";
}
 
<h2>Index</h2>
 
<p>
    @Html.ActionLink("Create New""Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.FirstName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.LastName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Designation)
        </th>
        <th></th>
    </tr>
 
@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.FirstName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.LastName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Designation)
        </td>
        <td>
            @Html.ActionLink("Edit""Edit"new { id=item.Id }) |
            @Html.ActionLink("Details""Details"new { id=item.Id }) |
            @Html.ActionLink("Delete""Delete"new { id=item.Id })
        </td>
    </tr>
}
 
</table>

[코드8] Index




@model NHibernateTest.Models.Employee
 
@{
    ViewBag.Title = "Edit";
}
 
<h2>Edit</h2>
 
 
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>Employee</h4>
        <hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.Id)
 
        <div class="form-group">
            @Html.LabelFor(model => model.FirstNamenew { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.FirstName)
                @Html.ValidationMessageFor(model => model.FirstName)
            </div>
        </div>
 
        <div class="form-group">
            @Html.LabelFor(model => model.LastNamenew { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.LastName)
                @Html.ValidationMessageFor(model => model.LastName)
            </div>
        </div>
 
        <div class="form-group">
            @Html.LabelFor(model => model.Designationnew { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Designation)
                @Html.ValidationMessageFor(model => model.Designation)
            </div>
        </div>
 
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}
 
<div>
    @Html.ActionLink("Back to List""Index")
</div>
 
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

[코드9] Edit




@model NHibernateTest.Models.Employee
 
@{
    ViewBag.Title = "Details";
}
 
<h2>Details</h2>
 
<div>
    <h4>Employee</h4>
	<hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.FirstName)
        </dt>
 
        <dd>
            @Html.DisplayFor(model => model.FirstName)
        </dd>
 
        <dt>
            @Html.DisplayNameFor(model => model.LastName)
        </dt>
 
        <dd>
            @Html.DisplayFor(model => model.LastName)
        </dd>
 
        <dt>
            @Html.DisplayNameFor(model => model.Designation)
        </dt>
 
        <dd>
            @Html.DisplayFor(model => model.Designation)
        </dd>
 
    </dl>
</div>
<p>
    @Html.ActionLink("Edit""Edit"new { id = Model.Id }) |
    @Html.ActionLink("Back to List""Index")
</p>

[코드10] Details




@model NHibernateTest.Models.Employee
 
@{
    ViewBag.Title = "Delete";
}
 
<h2>Delete</h2>
 
<h3>Are you sure you want to delete this?</h3>
<div>
    <h4>Employee</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.FirstName)
        </dt>
 
        <dd>
            @Html.DisplayFor(model => model.FirstName)
        </dd>
 
        <dt>
            @Html.DisplayNameFor(model => model.LastName)
        </dt>
 
        <dd>
            @Html.DisplayFor(model => model.LastName)
        </dd>
 
        <dt>
            @Html.DisplayNameFor(model => model.Designation)
        </dt>
 
        <dd>
            @Html.DisplayFor(model => model.Designation)
        </dd>
 
    </dl>
 
    @using (Html.BeginForm()) {
        @Html.AntiForgeryToken()
 
        <div class="form-actions no-color">
            <input type="submit" value="Delete" class="btn btn-default" /> |
            @Html.ActionLink("Back to List""Index")
        </div>
    }
</div>

[코드11] Delete




이제 모든 준비가 되었으니 확인해 보도록 한다.



이 프로젝테에서 사용하는 DB는 LocalDB V11 을 사용하였다. Hibernate.cfg.xml 파일에서  "AttachDbFileName" 부분을 자신의 환경에 맞게 수정해야 한다.




[그림2] List





[그림3] Edit





Source Download

NHibernateTest.zip





Model Binding using IModelBinder and DefaultModelBinder in ASP.NET MVC


참조 URL
  1. http://www.codeproject.com/Tips/806415/Model-Binding-using-IModelBinder-and-DefaultModelB

 


이 문서에 대하여

이 문서는 원본 문서를 읽고, 따라하고, 변경 또는 수정없이 인용한 부분이 있으며 주석이나 추가 설명에 대해 가감을 하였습니다. 이 문서와는 별개로 별도의 원본이 있음을 알려 드리며 원본에 대한 자세한 사항은 참조 URL에 있음을 알려 드립니다. 오역, 어색한 부분, 매끄럽지 않은 부분이 있을 경우 알려주시면 적극적으로 반영하도록 하겠습니다.



ASP.NET MVC에서 기본으로 제공되는 모델 바인더가 있어서 컨트롤러에서 클래스로 변환되어 사용할 수 있도록 해주고 있다. 일반적인 케이스에서는 잘 동작하고 있지만 모델과 HTML의 Name이 일치하지 않을경우 커스텀 모델 바인더를 통해 해결 할 수 있는 방법을 제공해 주고 있다. 'IModelBinder' 인터페이스를 상속받아 구현된 클래스를 통해 이와같은 기능을 대체할 수 있도록 한다. 


public interface IModelBinder
{
    object BindModel(ControllerContext controllerContextModelBindingContext bindingContext);
}

[코드1] IModelBinder interface



 IModelBinder 인터페이스는 object를 반환하는 BindModel이 선언되어 있어서 이 메소드만 구현하면 원하는 방법으로 바인딩을 할 수 있다. 우선 모델 클래스를 선언하는 것부터 시작하자!


public class Person
{
    [Required]
    [MaxLength(50ErrorMessage = "Full name should be within 50 character")]
    public string full_name { getset; }
 
    [Range(1880)]
    [Required(ErrorMessage = "Please provide age")]
    public Int32 Age { getset; }
}

[모드2] Person Model class



 위와 같이 모델 클래스를 선언하고 IModelBinder을 상속받아 아래와 같이 Form객체에서 값을 가져와 Person객체를 반환하는 코드를 작성하자.



public class PersonModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContextModelBindingContext bindingContext)
    {
        var request = controllerContext.HttpContext.Request;
 
        string first_name = request.Form.Get("first_name");
        string middle_name = request.Form.Get("middle_name");
        string last_name = request.Form.Get("last_name");
        int Age = Convert.ToInt32(request.Form.Get("age"));
        return new Person { full_name = first_name + middle_name + last_nameAge = Age };
    }
}

[코드3] PersonModelBinder class




 이제 웹페이지에서 확인할 수 있도록 UI 관련 코드를 작성하자. 아래와 같이 CustomodelbinderController 클래스를 작성하고 PostData View 페이지를 추가하자.



public class CustomodelbinderController : Controller
{
    //
    // GET: /Customodelbinder/
    public ActionResult Index()
    {
        return View();
    }
 
    public ActionResult PostData()
    {
        return View();
    }
 
    [HttpPost]
    public void PostData([ModelBinder(typeof(PersonModelBinder))] Person person)
    {

    }

[코드4] CustomodelbinderController class


 위 코드에서 주의할 부분이 PostData의 입력 인자에서 Parameter Attribute를 선언하여 명시적으로 PersonModelBinder를 사용하도록 선언을 해야 한다.



@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <div>
        @{Html.BeginForm("PostData""Customodelbinder");
        <table>
            <tr>
                <td>First Name : </td>
                <td>@Html.TextBox("first_name")</td>
            </tr>
            <tr>
                <td>Middle Name : </td>
                <td>@Html.TextBox("middle_name")</td>
            </tr>
            <tr>
                <td>Surname :</td>
                <td> @Html.TextBox("last_name")</td>
            </tr>
            <tr>
                <td>Age:</td>
                <td> @Html.TextBox("age"</td>
            </tr>
            <tr>
                <td></td>
                <td>
                    <input type="submit" name="Save" value="Save" />
                </td>
            </tr>
        </table>
        }
    </div>
</body>
</html>

[코드5] CustomodelbinderController 의 PostData View 페이지



이제 완료가 되었으니 "http://localhost:????/Customodelbinder/PostData"와 같은 주소로 지금까지의 코드를 확인해 보도록 하자.



[그림1] 입력 화면







[그림2] PersonModelBinder 값 확인




[그림3] Controller에서 값 확인



 위와 같이 ModelBinder 단과 Controller단에서 기대하는 값을 확인 할 수 있다.





사용자가 수정한 커스텀 바인더를 ASP.NET MVC에서 인식하여 사용할 수 있는 방법이 아래오 같이 두가지가 있다.


  1. Parameter Attribute

  2. Global.asax에서 ModelBinders에 등록


첫번째는 위 "코드4"에서 언급이 되었듯 

public void PostData([ModelBinder(typeof(PersonModelBinder))] Person person)

이 사용할 수 있고 아래와 같이 추가하여 사용할 수 있다.

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
 
        ModelBinders.Binders.Add(typeof(Person), new PersonModelBinder()); // <- 추가 코드
    }
}

[코드6] Global.asax









여담으로 IModelBinder 인터페이스 대신에 DefaultModelBinder 클래스를 상속받아 같은 기능을 실현 할 수 있다.

public class PersonDefaultModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContextModelBindingContext bindingContext)
    {
        var request = controllerContext.HttpContext.Request;
 
        string first_name = request.Form.Get("first_name");
        string middle_name = request.Form.Get("middle_name");
        string last_name = request.Form.Get("last_name");
        int Age = Convert.ToInt32(request.Form.Get("age"));
        return new Person { full_name = first_name + middle_name + last_nameAge = Age };
    }
}





Source Download


IModelBinderWebApplication.zip







새로운 버전의 ASP.NET MVC 5.2, Web API 2.2 and Web Pages 3.2가 발표가 되었다


참조 URL
  1. http://blogs.msdn.com/b/webdev/archive/2014/07/02/announcing-the-release-of-asp-net-mvc-5-2-web-api-2-2-and-web-pages-3-2.aspx

 



이 문서에 대하여

이 문서는 원본 문서를 읽고, 따라하고, 변경 또는 수정없이 인용한 부분이 있으며 주석이나 추가 설명에 대해 가감을 하였습니다. 이 문서와는 별개로 별도의 원본이 있음을 알려 드리며 원본에 대한 자세한 사항은 참조 URL에 있음을 알려 드립니다. 오역, 어색한 부분, 매끄럽지 않은 부분이 있을 경우 알려주시면 적극적으로 반영하도록 하겠습니다.





 2014.07.02에 "ASP.NET MVC 5.2, Web API 2.2 and Web Pages 3.2"에 새로운 버전이 발표가 되면서 자잘한 기능들에서 개선 사항들이 반영이 되었으며 Web Pages 3.2.1에서는 성능 적인 면에서 기존보다 개선되어 있는 것을 확인할 수 있다. ( http://www.asp.net/web-pages/overview/releases/whats-new-in-aspnet-web-pages-321 )



  • ASP.NET MVC 5.2

    • 개선된 Attribute 라우팅

    • 기능 업데이트

    • 버그 수정

  • ASP.NET Web API 2.2

    • OData V4 지원

    • 개선된 Attribute 라우팅

    • Windows Phone 8.1용 클라이언트 지원

    • 기능 업데이트

    • 버그 수정

  • ASP.NET Web Pages 3.2

    • 기능 업데이트

    • 버그 수정




이 버전을 프로젝트에 반영하기 위해서는 아래와 같이 PM에서 실행해 주면 된다.


  • Install-Package Microsoft.AspNet.Mvc -Version 5.2.0
  • Install-Package Microsoft.AspNet.WebApi -Version 5.2.0
  • Install-Package Microsoft.AspNet.WebPages -Version 3.2.0













Knockout Generator


참조 URL
  1. http://visualstudiogallery.msdn.microsoft.com/32c15a80-1c54-4e96-a83f-7cd57573a5d2

 

 "Andreas Gustafsson" 님이 만든 Knockout Generator 툴을 이용해서 C#에사 만든 클래스를 이용해서 쉽게 javascript의 클래스를 만들 수 있도록 지원해 준다. 이 툴을 설치 하려면 우선 Visual studio 에서 Tools > Extensions and Updates... 클릭해 "그림1"과 같은 화면을 띄워 "knockout"으로 검색하면 "Knockout Generator"이 보일 것이다. 이 부분 설치하고 Visual studio를 재 실행하면 활성화가 된다.

 

 

 

[그림1] Knockout Generator 검색 결과 화면

 

 

그런 후 솔루션 탐색기에서 특정 클래스위에서 오른쪽 클릭하면 "그림2"와 같은 메뉴를 확인할 수 있다.

 

 

[그림2] ViewModel 만드는 화면

 

 

 

클릭하고 All Obserable를 체크하고 "Copy to clipboard"를 눌러 메모리에 복사한다.

 

[그림3] javascript를 메모리에 복사하는 화면

 

 

 

그런 후 "그림4"와 같이 Visual studio 에서 javascript 아이템을 새로 추가한 후

 

[그림4] javascript 파일 추가

 

 

 

붙여넣기를 하면 "그림5"와 같은 javascript의 결과가 나오게 된다.

 

[그림5] knockout에서 사용할 javascript 파일

 

 

 

 위와 같은 방법으로 knockout에서 사용하는 모델을 쉽게 만들 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 











 

Web에서 HttpResponseException을 이용한 에러 노출


참조 URL
  1. http://msdn.microsoft.com/ko-kr/library/system.web.http.httpresponseexception(v=vs.118).aspx

 


example

throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);





아래 상태별로 표준 에러를 표현해 줄 수 있다.


Continue = 100,
SwitchingProtocols = 101,
OK = 200,
Created = 201,
Accepted = 202,
NonAuthoritativeInformation = 203,
NoContent = 204,
ResetContent = 205,
PartialContent = 206,
MultipleChoices = 300,
Ambiguous = 300,
MovedPermanently = 301,
Moved = 301,
Found = 302,
Redirect = 302,
SeeOther = 303,
RedirectMethod = 303,
NotModified = 304,
UseProxy = 305,
Unused = 306,
RedirectKeepVerb = 307,
TemporaryRedirect = 307,
BadRequest = 400,
Unauthorized = 401,
PaymentRequired = 402,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
ProxyAuthenticationRequired = 407,
RequestTimeout = 408,
Conflict = 409,
Gone = 410,
LengthRequired = 411,
PreconditionFailed = 412,
RequestEntityTooLarge = 413,
RequestUriTooLong = 414,
UnsupportedMediaType = 415,
RequestedRangeNotSatisfiable = 416
ExpectationFailed = 417,
UpgradeRequired = 426,
InternalServerError = 500,
NotImplemented = 501,
BadGateway = 502,
ServiceUnavailable = 503,
GatewayTimeout = 504,
HttpVersionNotSupported = 505,













+ Recent posts