잊지 않겠습니다.

1. Preview 3/4의 uninstall.

: global에 등록되어있는 System.Web.Routing, System.Web.Mvc, System.Web.Abstractions에 대한 완벽한 uninstall이 필요하다.

: 프로그램 추가/삭제에서의 제거 뿐 아닌, Registery에서  HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Installer\Assemblies\Global에서의 완벽 제거가 필요

  

2. Namespace의 이전

: Html.ActionLink<Controller>의 Namespace가 System.Web.Mvc에서 Microsoft.Web.Mvc로 이전

  

3. RenderUserControl의 제거

RenderPartial로 함수 이름 변경

: 전에는 string을 이용한 Html의 표현 방식이였으나, 이제는 함수 형태로 변경

  

4. web.config 수정

: 버젼 정보 0.0.0.0을 모두 3.5.0.0으로 변경 

Posted by Y2K
,

HTTP에서의 File upload

: form에서의 post 방식을 통한 File을 업로드시키게 된다.

   <form action="/home/uploadfiles" method="post" enctype="multipart/form-data">  
        <label for="file">Filename:</label>  
        <input type="file" name="file" id="file" />  
           <input type="submit" name="submit" value="Submit" />  
   </form>  

 

POST를 통해서 HTTP Header에 같이 넣어지는 데이터는 다음과 같다.

 

POST /home/uploadfiles HTTP/1.1
Content-Type: multipart/form-data; boundary=---------------------------7d81b516112482
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64)
Content-Length: 324

-----------------------------7d81b516112482
Content-Disposition: form-data; name="file"; filename="\\SERVER\Users\Scott\Documents\test.txt"
Content-Type: text/plain

foo
-----------------------------7d81b516112482
Content-Disposition: form-data; name="submit"

Submit
-----------------------------7d81b516112482--

 

POST를 통해서 이동되는 데이터에서는 하나 이상의 파일이 multipart/form-data를 통해서 얻어지는 것이 가능하게 된다. 또한 POST를 통해서 Header에 각각의 binary data가 저장되게 된다.

multipart/form-data를 통하지 않은 데이터는 다음과 같이 보여지게 된다.

POST /home/uploadfiles HTTP/1.1
Content-Type: application/x-www-form-urlencoded
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64)
Content-Length: 13

submit=Submit

 

차이가 확연히 보이는 것을 알수 있다. File의 업로드 시에 필요한 File의 데이터에 대한 정보는 존재하지 않고 있다.ASP.NET에서의 FileUpload control의 경우에도 역시 form에서의 multipart/form-data를 통해서 데이터를 전송시키고 있다.

 

이때에 Http-Header의 정보에 있는 데이터를 얻어오는 방법은 다음과 같다.

                HttpPostedFileBase hpf = Request.Files[file] as HttpPostedFileBase;  
                if (hpf.ContentLength == 0)  
                    continue;  

                string savedFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Path.GetFileName(hpf.FileName));  
                hpf.SaveAs(savedFileName);

 

요청되어진 Request에서 Files property는 multipart/form-data에서 얻어진 파일 이름과 그에 따른 File 값들로 구성되어진다. HttpPostedFileBase로 데이터를 받아서 서버단이나 원하는 위치에 지정하게 되면 저장되게 된다.

 

이러한 방법은 ASP.NET 또는 MVC 모델에서 뿐 아니라, HTTP단에서 Post를 이용한 데이터의 전송시에 항시 사용되는 방법이 된다.


Posted by Y2K
,

오늘 회사에서 대성씨의 REST에 대한 소개와 REST URI에 대한 내용을 들으면서 전부터 posting 할려고 했던 내용을 Posting 해보자 싶었다. 

  

일단, ASP.NET MVC Framework와 동일하게 진행되었던 ASP .NET의 프로젝트중 하나가 ASP.NET에서의 RESTFUL 이용 방법이였고, 이러한 방법자체가 ASP .NET MVC Framework에 같이 통합이 되어있는 상태이다.

  

기본적으로 Route에 추가하는 RouteHandler에서 회사에서 사용되는 uri.py의 기능과 동일한 기능을 사용하게 된다.

예를 들어.. User/Details/456 이라는 sub-uri를 보게 되면, User-Detail-ID 의 형태를 가지고, User의 Detail한 상태를 알아 볼 수 있는 URI에서의 정보를 제공할 수 있게 된다.

  

MVC에서 RouteHandler가 움직이는 원리는 다음에 포스팅 하기로 하고... 일단은 ASP .NET에서 권장하는 기본적인 Controller의 Action method name, 즉 동작(Action)에 대한 기본 명명법은 다음과 같다.

Action

Sample URL

Description

Details

/Product/Details/5

Displays a single resource such as a database record. For example, displays a single Product with an Id of 5.

Index

/Product/Index

Displays a collection of resources. For example, displays all of the products in the products database table.

Create

/Product/Create

Displays a form for creating a new resource. For example, displays a form for creating a new product.

Insert

/Product/Insert

Inserts a new resource into the database. Typically, you redirect to another action after performing an Insert.

Edit

/Product/Edit/5

Displays a form for editing an existing resource. For example, displays a form for editing a product with an Id of 5.

Update

/Product/Update/5

Updates existing resources in the database. Typically, you redirect to another action after performing an Update.

Destroy

/Product/Destroy/5

Displays a page that confirms whether or not you want to delete a resource from the database.

Delete

/Product/Delete/5

Deletes a resource from the database. Typically, you redirect to another action after performing a Delete.

Login

/Home/Login

Displays a login form.

Logout

/Home/Logout

Logs out a user. Typically, you redirect to another action after performing a Logout.

Authenticate

/Home/Authenticate

Authenticates a user name and password. Typically, you redirect to another action after performing an Authenticate.

  

 여기에서 주목할 점이, Update와 Delete, Destroy이다. REST에서 권장하는 HttpMethod인 PUT과 DELETE를 사용하지 않는 이유는 기본적인 ASP.NET MVC Framework에서는 PUT과 DELETE를 사용하고 있지 않기 때문이다. 기본적인 설정에서 사용하고 있지 않는 설정을 권장사항에 넣기 힘들어서 아무래도 Update와 Delete가 따로 Action으로 분류를 시키고 있는 것 같다. 

  

기본적인 MapRoute 방법자체는 다음과 같다.

             routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );

 각각의 Route의 이름과 Controller, Action, 그리고 필요하다면 그에 따른 parameter의 이름을 이용한 MapRoute를 작성시키고 있다. 여기에서 {controller}의 이름은 RegularExpression을 지원하기 때문에, 기본적인 REST 서버들과 거의 유사하게 움직인다. (정확히는 모른다. --)

Posted by Y2K
,

ASP .NET MVC Framework에서는 URL에 대한 각각의 Controller를 기본적으로 다음과 같이 사용하고 있다.

 

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );

 

여기에서, 각각의 Route는 기본적으로 Controller/Action/Parameters 형태로서 구성이 되지만, 다음과 같이 다른 형태의 Route역시 가능하다.

 

http://localhost/Product/Create/id          
  routes.MapRoute(
                "Product",                                              // Route name
                "Product/{action}/{id}",                           // URL with parameters
                new { controller = "ProductManager", action = "List", id = "" }  // Parameter defaults
            );


http://localhost/Product/id/Edit

routes.MapRoute(   
                 "ProductEdit",        // Route name  
                 "Product/{id}/Edit",  // URL with parameters     
                 new { controller = "ProductManager", action = "Edit", id = "" }  // Parameter defaults 
           );

 

Caution!!!

Route를 여러개 지정하는 경우에는 차례대로 먼저 알아보게 된다. 기본적인 Controller를 가장 최 상단으로 올리는 경우에 그 뒤에 나오는 모든 sub-url을 기본적으로 controller로 해석하려고 하기 때문에 무조건 에러가 발생하게 된다.

사용자 지정 URL을 넣어주는 경우에는 먼저, 사용자 URL을 먼저 넣어주고 그 후에 기본적으로 사용하는 Default Route를 넣어주는 것이 하나의 방법이 된다.

Posted by Y2K
,

JSON 형태의 데이터를 C# 형태로의 변환

  

java script에서나 Netscape 진형에서 주로 사용되는 JSON 데이터 형태를 C# class로 변환 및 이를 이용한 AJAX 개발이 가능하다.  

  

먼저, C# class의 선언

  1. public class Company  
  2.     {  
  3.         public string Name { getset; }  
  4.         public string Location { getset; }  
  5.         public string Subject { getset; }  
  6.     }  

  

여기서 간단히 3개의 Input box를 갖는 View Page의 생성

  1. <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="CompanyView.aspx.cs" Inherits="MvcJson.Views.Home.CompanyView" %>  
  2. <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">  
  3. Company Name : <%=Html.TextBox("CompanyName") %> <br />  
  4. Company Subject : <%=Html.TextBox("Subject") %> <br />  
  5. Company Location : <%=Html.TextBox("Location") %> <br />  
  6. <input type="button" id="sendCompanyData" value="Send Company Data" /><br />  
  7. <div id="resultArea"></div>  
  8. </asp:Content>  


HttpContext를 이용해서 json data를 HTTP-POST로 전달하는 javascript

(jQuery 이용.) 

  1. <script type="text/javascript" src="<%= Url.Content("~/Scripts/jquery-1.2.6.js") %>"></script>  
  2. <script type="text/javascript" src="<%= Url.Content("~/Scripts/jquery.toJSON.js") %>"></script>  
  3. <script type="text/javascript">  
  4.   $(function() {  
  5.     //sending json object to controller action:  
  6.     $("#sendCompanyData").click(function() {  
  7.       var company = {  
  8.         "Name": $("#CompanyName").val(),  
  9.         "Subject": $("#Subject").val(),  
  10.         "Location": $("#Location").val()  
  11.       };  
  12.   
  13.       var encoded = $.toJSON(company);  
  14.   
  15.       $.ajax({  
  16.         url: "/Home/ShowCompany",  
  17.         type: "POST",  
  18.         dataType: 'json',  
  19.         data: encoded,  
  20.         contentType: "application/json; charset=utf-8",  
  21.         beforeSend: function() { $("#saveStatus").html("Saving").show(); },  
  22.         success: function(result) {  
  23.           alert(result.Result);  
  24.           $("#saveStatus").html(result.Result).show();  
  25.         }  
  26.       });  
  27.     });  
  28.   });   
  29. </script>  

  

데이터를 받을 Controller 작성

  1. public ActionResult ShowCompany()  
  2.         {  
  3.             if(HttpContext.Request.ContentType.Contains("application/json"))  
  4.             {  
  5.                 string inputContent;  
  6.                 int dataLength = (int) HttpContext.Request.InputStream.Length;  
  7.                 byte[] btDatas = new byte[dataLength];  
  8.                 HttpContext.Request.InputStream.Read(btDatas, 0, dataLength);  
  9.   
  10.                 inputContent = System.Text.Encoding.UTF8.GetString(btDatas);  
  11.   
  12.                 var result = (Company) JavaScriptConvert.DeserializeObject(inputContent, typeof(Company));  
  13.   
  14.                 return Json(new { Result = string.Format("{0} : {1} : {2}", result.Name, result.Subject, result.Location) });  
  15.             }  
  16.             else  
  17.             {  
  18.                 return Json(new { Result = "This data is not json" });  
  19.             }  
  20.         }  

  

결론 : JSON -> C# class 변환은 매우 자유로운 편이다. 예시의 JSON이 있다면 C# class를 자동으로 작성해주는 간단한 script만 있으면 둘이 같이 사용하기가 매우 편할것 같다.

Posted by Y2K
,

web에서 인증을 도와주고, 인증을 이용한 ActionFilter를 제공한다. 

  

1. web.config의 설정

   <authentication mode="Forms">
      <forms loginUrl="~/NotLogOn" />
    </authentication>

authentication mode는 반드시 Forms로 해주고, authorize가 되어있지 않는 경우에 돌아갈 url을 설정한다.

  

2. Login 정보 입력

FormsAuthentication 을 이용해서 user정보를 저장하는 cookie 값을 이용한다.  

   public interface IFormsAuthentication
    {
        void SetAuthCookie(string userName, bool createPersistentCookie);
        void SignOut();
    }
    public class FormsAuthenticationWrapper : IFormsAuthentication
    {
        public void SetAuthCookie(string userName, bool createPersistentCookie)
        {
            FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
        }
        public void SignOut()
        {
            FormsAuthentication.SignOut();
        }
    } 

  

3. Login 정보 입력 부분 구현

       public ActionResult Logon(string userName, string password, string saveCookie)
        {
            if(Request.HttpMethod != "POST")
            {
                return Redirect("/Logon/Index");
            }
            HostwayMembership membership = new HostwayMembership();
            if( membership.ValidateUser(userName, password) )
            {
                FormsAuth.SetAuthCookie(userName, saveCookie == "on");
                csDB.CreateCSEvent(userName, com.hostway.lib.SYNCmail.Database.CSEventCase.CSUserLogin, userName,
                                   "Logon", "Logon user");
                csDB.OnSubmit();
                return Redirect("/Home/Index");
            }
            else
            {
                return Redirect("/Logon/Index");
            }
        }

  

4. 인증이 필요한 controller, 또는 action에 attribute 적용

   [Authorize(Order=0)][AuthActionFilter(Order=1)]
    public class UserController : SYNCmailController
    [Authorize]
    public ActionResult List(int? pageNumber, int? eventPageNumber)

  

controller에 적용되는 경우에는 모든 action에 일괄적으로 적용되게 된다. 

이때에, Order 순서를 정해서 적용될 ActionFilter의 순서를 결정할 수 있다.

  

또한, 아래와 같이 user 또는 , Role에 대해서도 역시 같은 적용이 가능하다.

[Authorize(Users="email@address.co.kr")] 
[Authorize(Roles="admin, friend")]

  

  

  

  

  

Posted by Y2K
,

Action Result

.NET Framework 2009. 1. 7. 13:00

Controller에서 View에게 명령을 넘겨주는 Action에 대한 결과값

 

Method

  • View : return ViewResult instance
    • View를 호출하는 경우에는 Controller가 동작하지 않는다. View()가 되는 순간에 View가 호출이 되고, 단지 보여지는 방법을 공유할때 사용된다.(url이 변경되지 않는다.)
  • Redirect : redirects to the specified URL. Returns a RedirectResult result
    • Controller가 실행되고, url이 변경되게 된다.
  • RedirectToAction : Accepts an action and redirects to another controller action. Returns aRedirectToRouteResult instance,
  • RedirectToRoute : Redirects to a ULR that is determined by the routing API. this method lets you specify a named route. Returns a RedirectToRouteResult instance.
  • Json : Return JsonResult instance.
  • Content : send text context to the response. Returns a ContentResult instance.

 

ActionResult Type

  • ViewResult : Renders the specified view to the response.
  • EmptyResult : Does nothing. return null instance.
  • RedirectResult : Performs an HTTP redirect to the specified URL.
    • - controller가 있는 경우 controller method가 실행되고, 그 결과가 리턴되게 된다.
  • RedirectToRouteResult : Given some routing values, uses the routing API to determine tue URL and then redirects to that URL
  • JsonResult : Serializes the specified ViewData object to JSON format
  • ContentResult : Writes the specified text context to the response.

 

Posted by Y2K
,

Action Filter

.NET Framework 2009. 1. 7. 12:59

OnActionExecuting

 : just before the action method is called.

OnActionExecuted

 : just after the action method is called.

OnResultExecuting

 : occurs just before the result is executed. : before view is rendered.

OnResultExecuted

 : occurs after the result is executed. : after the view is rendered.

 

 public class AuthActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpCookie idCookie = filterContext.HttpContext.Request.Cookies.Get("id");
        HttpCookie passwordCookie = filterContext.HttpContext.Request.Cookies.Get("password");

        if ( filterContext.HttpContext.Session[ "Auth" ] == null || ( bool )filterContext.HttpContext.Session[ "Auth" ] == false )
        {
            if ( idCookie != null && passwordCookie != null )
            {
                HostwayMembership membership = new HostwayMembership();
                if ( membership.ValidateUser(idCookie.Value, passwordCookie.Value) )
                {
                    filterContext.HttpContext.Session[ "Auth" ] = true;
                    string authUserName = membership.GetUserName(idCookie.Value, passwordCookie.Value);
                    filterContext.HttpContext.Session["UserName"] = authUserName;
                    using(SYNCmailCSDatabase csDB = new SYNCmailCSDatabase())
                    {
                        csDB.CreateCSEvent(authUserName, 
                            com.hostway.lib.SYNCmail.Database.CSEventCase.CSUserLogin, authUserName,
                            "Logon", "Logon user");
                    }
                }
            }
        }
        
        if ( filterContext.HttpContext.Session[ "Auth" ] == null || (bool) filterContext.HttpContext.Session[ "Auth" ] == false)
        {
            filterContext.Cancel = true;
            filterContext.HttpContext.Response.Redirect("~/Logon/Index");
        }
        else
        {
            string userName = (string) filterContext.HttpContext.Session[ "UserName" ];
            string actionMethodName = filterContext.ActionMethod.Name;
            
            using(SYNCmailCSDatabase csDB = new SYNCmailCSDatabase())
            {
                string comment = string.Format("{0} user action method : {1}", userName, actionMethodName);
                csDB.CreateCSEvent(userName, CSEventCase.EnterPage, actionMethodName, filterContext.HttpContext.User.Identity.Name, comment);
            }
            base.OnActionExecuting(filterContext);
        }
    }
}

 

 

 

 


Posted by Y2K
,