여러개의 파일을 업로드 해보자.

현재 주소 복사
트랙백 주소 복사
방실이님의 글 (7/28/2006 10:17:14 AM) Viewing : 5363

이 사이트에서 구현되어 있는거다..
파일을 여러개 선택해서..
한번에 인서트 하는 법을 알아 보겠다...

먼저 txtFile이라는 파일 컨트롤을 하나 만든다..(사이트의 구현은 이전 버전인 Html 컨트롤이다..별 차이 없으리라 본다.)
그리고 사용자가 선택한 파일리스트를 보여줄 리스트박스 하나 더 추가한다.
그럼 준비는 끝..

먼저 AddFile()이라는 메소드를 보면..(사실 이게 전부..ㅡ.ㅡ;)
(이 부분이 이해가 안간다면 자신의 스크립트 실력이 딸려서 그런것이다..MSDN이나 KOXO.com등의 사이트에서 관련 스크립트에 대해 검색해서 참고 하기 바란다.)
기존에 만들어 놓은 txtFile의 클라이언트 아이디를 얻어와서..
사용자가 파일 추가 버튼을 누르게 되면..새로운 파일 컨트롤을 동적으로 생성 시킨다.
그리고 기존에 보여지는..파일컨트롤을 display= none으로 변경 시킨다..
사용자의 입장에서 UI부분의 변경은 전혀 없으나..단지 파일 컨트롤의 value의 문자열이 사라졌다는 거..정도??
사용자가 보고 있는 컨트롤은 이전부터 있어왔던 컨트롤이 아니라 스크립트로 동적으로 새로 생성된 컨트롤이다..

OK~~..


[소스코드]


    var fileCount=0;
    function AddFile()
    {
        var txtFile = eval(document.all['ctl00$ContentPlaceHolder1$txtFile'+fileCount]);
        if(FileValidate(txtFile))
        {
            AddInList(txtFile);
            var newInputFile = document.createElement("<input name='ctl00$ContentPlaceHolder1$txtFile"+Number(++fileCount)+"'>");
            newInputFile.type = "file";
            newInputFile.className="input_text";
            newInputFile.style.width="412px";
            newInputFile.style.height="20px";
            txtFile.insertAdjacentElement("afterEnd", newInputFile);
            txtFile.style.display = 'none';
        }
    }

    function AddInList(txtFile)
    {
        var select = eval(document.all['selectList']);
        select.options[select.options.length] = new Option(txtFile.value, txtFile.name, false, true);    
    }

    function RemoveFile()
    {    
        var select = eval(document.all['selectList']);
        if(select.selectedIndex <0)
        {
            alert(''삭제할 파일을 선택 하세요.'');
        }
        else
        {
            var id = select.options[select.selectedIndex].value;
            eval(document.all[id]).removeNode();
            select.options[select.selectedIndex] = null;
        }
    }

    function FileValidate(txtFile)
    {
        if(txtFile.value == '')
        {     
            alert('파일을 선택 하지 않았습니다\n파일 선택후 추가해 주세요.');   
            return false;
        }
        var imgSize = 1024 * 1024 * 10;
        var img = new Image();
        img.dynsrc = txtFile.value;
        if(img.fileSize < 0)
        {
            alert('알 수 없는 파일 사이즈 입니다.');
            return false;
        }
        else if(img.fileSize > imgSize)
        {
            alert(imgSize+'바이트 이상의 파일은 업로드 할 수 없습니다.');
            return false;
        }
        return true;
    }

    function DeleteFile(ctl, fileId)
    {
        var deleteFileList = eval(document.all['<%=txtDeleteFileList.ClientID %>']);
        if(ctl.checked)
        {
            deleteFileList.value += fileId+'&';
        }
        else
        {
            deleteFileList.value = deleteFileList.value.replace('&'+fileId+'&','&');        
        }
    }

나머지는 유효성을 체크하고 선택된 파일 삭제하고 하는 부분이다..
뭐 어려운 코드는 아니니...

이제 서버단에서 어떻게 처리를 해야 할까...

cs파일에서 아래 코드 처럼 비즈니스레이어의 메소드를 호출한다.(30번 라인)
넘기는 파라메터는 업로드할 경로와 해당 포스트의 아이디와 Request.Files 컬렉션이다.


[소스코드]

    1     /// <summary>

    2     /// Saves the specified board.

    3     /// </summary>

    4     /// <param name="board">The board.</param>

    5     /// <returns></returns>

    6     private BoardMessage Save(BoardBiz board)

    7     {

    8         string postId = "";

    9         string content = "";

   10         string title = this.txtTitle.Text.Trim();

   11         if (this.rblIsText.SelectedIndex == 0)

   12         {

   13             content = this.txtTextContent.Text.Trim();

   14         }

   15         else

   16         {

   17             content = this.txtHtmlContent.Value.Trim();

   18         }

   19         if (this.IsAuthenticated)

   20         {

   21             postId = board.Insert(this.BoardCategoryId, this.Context.User.Identity.Name, this.Profile.RealName, null, null, title, content, this.chbNotice.Checked, (this.rblIsText.SelectedIndex == 0), this.trPostCategory.Visible ? Convert.ToInt32(this.ddlCategory.SelectedValue) : 0);

   22         }

   23         else

   24         {

   25             this.Profile.RealName = this.txtName.Text.Trim();

   26             this.Profile.EMail = this.txtMail.Text.Trim();

   27             postId = board.Insert(this.BoardCategoryId, null, this.txtName.Text.Trim(), this.txtPassword.Text.Trim(), this.txtMail.Text.Trim(), title, content, this.chbNotice.Checked, (this.rblIsText.SelectedIndex == 0), this.trPostCategory.Visible ? Convert.ToInt32(this.ddlCategory.SelectedValue) : 0);

   28         }

   29         new RssWriter(this.Server.MapPath("RSS/" + this.BoardCategoryId.ToString() + ".xml"), this.BoardCategoryId.ToString(), "Bangsil's Homepage의 " + this.BoardCategoryItem.Name, "Bangsil's Homepage의 " + this.BoardCategoryItem.Name + " 입니다.");

   30         return board.FileUpload(this.Server.MapPath(System.Web.Configuration.WebConfigurationManager.AppSettings["FileUploadPath"]), new Guid(postId), this.Request.Files);

   31     }



거의 다 왔다..ㅋ

아래 코드가 서버로 업로드 하는 코드이다..
이 부분은 사용자의 취향(??)에 따라 모두 다르리라 생각한다.
받은 컬렉션에서 루프를 돌아서..
파일을 세이브 하고 관련 데이터를 디비에 저장하는 코드이다..
별로 어려울것은 없다.


[소스코드]

    1     /// <summary>

    2     /// Files the upload.

    3     /// (0:정상처리, 1:업로드 오류, 2:데이터인서트 오류)

    4     /// </summary>

    5     /// <param name="path">The path.</param>

    6     /// <param name="postId">The post id.</param>

    7     /// <param name="files">The files.</param>

    8     /// <returns></returns>

    9     public BoardMessage FileUpload(string path, Guid postId, HttpFileCollection files)

   10     {

   11         List<BoardFileItem> fileList = new List<BoardFileItem>();

   12         bool hasFile = false;

   13         int result = 0;

   14 

   15         for (int i = 0; i < files.Count; i++)

   16         {

   17             if (files[i] != null)

   18             {

   19                 if (files[i].InputStream.Length > 0 && files[i].FileName != "")

   20                 {

   21                     BoardFileItem item = new BoardFileItem(postId);

   22                     item.RealFileName = files[i].FileName.Substring(files[i].FileName.LastIndexOf("\\") + 1);

   23                     item.VirtualFileName = Guid.NewGuid().ToString().Replace("-", "");

   24                     item.CreateDate = DateTime.Now;

   25                     item.Size = files[i].ContentLength;

   26                     item.ContentType = files[i].ContentType;

   27 

   28                     try

   29                     {

   30                         files[i].SaveAs(path + item.VirtualFileName);

   31                     }

   32                     catch

   33                     {

   34                         result = 1;

   35                     }

   36                     fileList.Add(item);

   37                     hasFile = true;

   38                 }

   39             }

   40         }

   41         if (hasFile && result == 0)

   42         {

   43             if (!this.AddFile(fileList, postId))

   44             {

   45                 result = 2;

   46             }

   47         }

   48         switch (result)

   49         {

   50             case 0:

   51                 return new BoardMessage(Message.InsertOK);

   52             case 1:

   53                 return new BoardMessage(Message.FileUploadError);

   54             default:

   55                 return new BoardMessage(Message.UnKnownError);

   56         }

   57     }




구현환경
.NET Framework 2.0
Microsoft Visual Studio.NET 2005
Microsoft Windows XP SP2



마지막 업데이트 : (12/12/2006 1:04:25 PM)

TAG : 없음



Trackback 보기 (0)
댓글 보기 (7)
이방은님의 글 (7/16/2007 10:28:22 AM)
참고로 위 스크립트 태그는 IE 7.0에서는 먹히지 않습니다..
img.dynsrc 태그 때문입니다..^^;;
dynsrc 태그가..권한 문제 때문에 IE 7.0에서는 막혔군요..^^;



이석님의 글 (8/31/2007 3:39:24 PM)
어...이건 첨부파일 없는거예요??
참고 할려고 했는데. 쩝.
저만의 허접스타일을 세련되게 바꿔볼려고 했는데.ㅋㅋ.
휴가 잘 보내세요.



이방은님의 글 (9/1/2007 3:06:02 PM)
ㅎㅎ
네 감사합니다..^^



이명규님의 글 (9/12/2007 5:37:08 PM)
display를 none로 바꾸게 되면 값이 전달이 안되던데..
새로생긴 파일 객체만 보여지는 것이라면 이전 파일객체가 넘어 가나요?



이방은님의 글 (9/13/2007 9:55:15 AM)
txtFile.style.display = 'none';
이 부분의 코드를 말씀 하신듯 합니다..^^;
display를 none으로 해도 분명이 값이 전달 됩니다..^^;
값이 전달되어야지..사용할 수가 있죠..
명규님 코드에 다른 문제가 있는 것은 아닌지요??



김희조님의 글 (10/2/2007 2:13:51 AM)
제가 바보라서 그런가요..ㅠㅠ

이해가 안가요.. 헉헉헉..ㅠㅠ 살려주세요.. 혹씨 첨부자료 같은건..ㅠㅠ



이방은님의 글 (10/2/2007 10:33:06 AM)
^^;
이긍...
첨부 자료는 만들지 않았습니다..^^;
어떤 부분이 이해가 안가시는지요..
하는데 까지 해보시고..
자유게시판에 질문을 주세요..



댓글 쓰기

동적으로 유저 컨트롤 추가 하기

현재 주소 복사
트랙백 주소 복사
방실이님의 글 (7/25/2006 9:40:59 AM) Viewing : 3706

먼저 유저 컨트롤 설정

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="OrderAddress.ascx.cs" Inherits="UserControls_OrderAddress" ClassName="UserControls_OrderAddress" %>

ClassName 속성을 이용하여 타입을 명확히 지정해 준다.

참조할 페이지에서

<%@ Reference Control="~/UserControls/OrderAddress.ascx" %>

레퍼런스를 추가 해 준다..
주 : 레퍼런스를 추가 해 주지 않으면 코드 페이지에서 인텔리센스가 작동하지 않는다.

cs에서 유저 컨트롤의 개체를 생성하기 위해서는 레퍼런스 대신 @Register 지시문을 이용하여 선언해 주어야 한다.

참조할 페이지의 cs에서

ASP.UserControls_OrderAddress uc = (ASP.UserControls_OrderAddress)this.LoadControl("../UserControls/OrderAddress.ascx");

this.phOrderAddress.Controls.AddAt(i, uc);

ASP 라는 네임스페이스가 붙으며 ascx 파일에서 선언된 클래스이름으로 찾는다..

PS. 버그가 있는듯 하다.

아무래도 버그인듯 한데..

이렇게 만들어 버리면..웹사이트 게시에..업데이트 가능 항목을 선택하게 되면..컴파일시 에러가 난다..

왜 그런지는 모르겠다..


마지막 업데이트 : (9/5/2006 10:09:37 AM)

TAG : 없음



Trackback 보기 (0)
댓글 보기 (0)
댓글 쓰기

캐시를 사용한 컨트롤의 경우는

현재 주소 복사
트랙백 주소 복사
방실이님의 글 (8/31/2006 4:15:02 PM) Viewing : 2347
유저 컨트롤에 아웃풋 캐시를 사용 하게 되면
생성되는 클래스가 변경된다.
PartialCachingControl이라는 클래스로 변경되는데
이 클래스를 유저 컨트롤의 클래스로 형변환 시키게 되면 캐스트예외가 발생하게 된다..

이 클래스에는 CashedControl이라는 프라퍼티가 존재하는데 처음에 캐쉬 될때를 제외 하고는 항상 null이다.
다시 말하면 다음 호출에서 캐쉬가 된 상황이라면 null을 반환 한다는 의미가 되겠다.

ASP 네임스페이스를 이용하든 리플렉션을 이용하든
캐시된 유저 컨트롤의 형을 가져 오기 위해서는 아래와 같은 작업을 해야 한다.

[소스코드]

Control ctl = this.LoadControl("~/UserControl/PostCategory.ascx");
this.PlaceHolder1.Controls.Add(ctl);


PostCategory uc = c.CachedControl as PostCategory;
if (uc == null)
{
    PartialCachingControl pcc = ctl as PartialCachingControl;
    if (pcc != null)
    {
        pcc.Test = "test";
    }
}
else
{
    uc.Test = "test";
}


구현환경
.NET Framework 2.0
Microsoft Visual Studio.NET 2005
Microsoft Windows XP SP2



마지막 업데이트 : (8/31/2006 4:15:02 PM)

TAG : 없음



Trackback 보기 (0)
댓글 보기 (0)
댓글 쓰기

리플렉션으로 접근 하는 방법..

현재 주소 복사
트랙백 주소 복사
방실이님의 글 (8/21/2006 10:31:19 AM) Viewing : 4776
이번에는 리플렉션을 이용해서 접근 해 보겠다.
리플렉션으로 이용 하는 방법은..
이런 이유에서 뿐만 아니라..
접근 할수 없는 한정자의 프라퍼티나 메소드(생성자 포함)에 접근할 수가 있어 파워풀 하다고 볼 수 있다.
그러나 리플렉션이라는게 후기바인딩(LateBinding)이므로 성능상의 약점은 있기 마련이다.

먼저 테스트 할 유저 컨트롤을 생성하고
테스트 할 프라퍼티와 메소드를 만들어 보기로 하겠다.


[소스코드]

    public string Test1()
    { 
        return "public method"; 
    }

    protected string Test2()
    {
        return "protected method";
    }

    public string Test3
    {
        get
        {
            return "public property";
        }
    }
        

아주..직관적인(??) 예제다 ..ㅋ~

이제 페이지단에서
이것들을 호출 해 보겠다.

먼저 코딩을 해보자.


[소스코드]

        Control ctl = this.LoadControl("UserControl/PostCategory.ascx");
        Type ty = ctl.GetType();
        MethodInfo info = ty.GetMethod("Test1", BindingFlags.NonPublic|BindingFlags.Public|BindingFlags.Instance);
        string str = ((string)info.Invoke(ctl, null));

먼저 LoadControl메소드로 컨트롤을 로드한다.
이때의 타입은 Control 이 된다.
일반적으로 페이지에 바인딩만 하려 하면 이 상태로 사용해도 절대 무방하나.
유저 컨트롤에 정의 되어 있는
프라퍼티나 메소드에 접근 하기 위해서는 타입을 명확히 해야 한다..

아무래도 뽀대상 ASP 네임스페이스로 사용하는 위의 방법 보다는..이게 폼이 날듯싶지만..
성능은 아무래도..위 방법이 나을듯..

암튼...
ctl 의 타입은 사용자가 만든 유저 컨트롤의 이름과 같은 타입을 가진다..
유저컨트롤_ascx 라는 타입이 된다.

ty의 GetMethod로 호출 할 메소드를 불러 온다.
이때 바인딩 플래그의 값에 따라 한정자가 틀려지게 되면 메소드를 검색 하지 못해 null을 반환하게 된다.
디버깅 해보면서 테스트 해보기 바란다.

마지막으로 MethodInfo의 개체에 잘 바인딩이 되었다면
Invoke메소드로 호출 하면 되겠다
Invoke메소드는 object형을 리턴하므로 명시적으로 형변환을 해줘야 한다..

이제 확인해 보면 str에는 public method라는 값이 들어 있는걸 볼 수 있다.


[소스코드]

        PropertyInfo p = ty.GetProperty("Test3", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        string s = (string)(p.GetGetMethod().Invoke(ctl, null));
//string s = (string)(p.GetValue(ctl, null));

프라퍼티의 경우에는 약간 다르다..
두가지 방법이 있는데
첫 번째는 주석 처리 되어 있는 부분처럼 GetValue()라는 메소드를 호출 하는 것이다.

또 하나의 방법은 ..
프라퍼티의 개념은 이전 버전의 언어인 C++의 get_메소드()와 전혀 다름이 없으며
실제로 IL코드 상에서는 get_메소드()로 번역된다.

그래서 리플렉션으로 프라퍼티를 읽게 되면 get_프라퍼티이름() 이라는 메소드로 호출이 되게 된다.
물론 set속성은 따로 있다.

위에 예제를 보면 p.GetGetMethod()라는 메소드를 호출 하게 되면
get_Test3()이라는 메소드로 리턴이 된다..
OK..

이제 위의 리턴된 메소드로 처음 했던 메소드를 불러들이는 것과 같은 방식으로
Invoke()로 호출 하게 되면
원하는 값인 public propery라는 값이 리턴된다.



구현환경
.NET Framework 2.0
Microsoft Visual Studio.NET 2005
Microsoft Windows XP SP2



마지막 업데이트 : (8/21/2006 1:15:03 PM)

TAG : 없음



Trackback 보기 (0)
댓글 보기 (1)
감사합니다.님의 글 (8/28/2009 9:12:45 AM)
참고가 됐습니다.



댓글 쓰기

포스트백시 오류 해결법

현재 주소 복사
트랙백 주소 복사
방실이님의 글 (7/25/2006 9:29:04 AM) Viewing : 3311

아래와 같은 오류가 뜬다...

해결법은 간단하다..

아래 나와 있는 설정을 바꿔 주면 된다.

EnableEventValidation="false"

''/''응용 프로그램에 서버 오류가 있습니다.

잘못된 다시 게시 또는 콜백 인수입니다. 이벤트 유효성 검사는 구성의 <pages enableEventValidation="true"/> 또는 페이지의 <%@ Page EnableEventValidation="true" %>를 사용하여 활성화됩니다. 이 기능은 다시 게시 또는 콜백 이벤트에 대한 인수가 원래 이들을 렌더링한 서버 컨트롤에서 발생하는지 확인하여 보안을 유지합니다. 데이터가 올바르면 유효성 검사에 대한 다시 게시 또는 콜백 데이터를 등록하는 데 ClientScriptManager.RegisterForEventValidation 메서드를 사용합니다.

설명: 현재 웹 요청을 실행하는 동안 처리되지 않은 예외가 발생했습니다. 스택 추적을 검토하여 발생한 오류 및 코드에서 오류가 발생한 위치에 대한 자세한 정보를 확인하십시오.

예외 정보: System.ArgumentException: 잘못된 다시 게시 또는 콜백 인수입니다. 이벤트 유효성 검사는 구성의 <pages enableEventValidation="true"/> 또는 페이지의 <%@ Page EnableEventValidation="true" %>를 사용하여 활성화됩니다. 이 기능은 다시 게시 또는 콜백 이벤트에 대한 인수가 원래 이들을 렌더링한 서버 컨트롤에서 발생하는지 확인하여 보안을 유지합니다. 데이터가 올바르면 유효성 검사에 대한 다시 게시 또는 콜백 데이터를 등록하는 데 ClientScriptManager.RegisterForEventValidation 메서드를 사용합니다.

소스 오류:

현재 웹 요청을 실행하는 동안 처리되지 않은 예외가 생성되었습니다. 아래의 예외 스택 추적을 사용하여 예외의 원인 및 위치 정보를 확인할 수 있습니다.


스택 추적:

[ArgumentException: 잘못된 다시 게시 또는 콜백 인수입니다. 이벤트 유효성 검사는 구성의 <pages enableEventValidation="true"/> 또는 페이지의 <%@ Page EnableEventValidation="true" %>를 사용하여 활성화됩니다. 
이 기능은 다시 게시 또는 콜백 이벤트에 대한 인수가 원래 이들을 렌더링한 서버 컨트롤에서 발생하는지 확인하여 보안을 유지합니다. 데이터가 올바르면 유효성 검사에 대한 다시 게시 또는 콜백 데이터를 등록하는 데 ClientScriptManager.RegisterForEventValidation 메서드를 사용합니다.] System.Web.UI.ClientScriptManager.ValidateEvent(String uniqueId, String argument) +2080153 System.Web.UI.Control.ValidateEvent(String uniqueID, String eventArgument) +106 System.Web.UI.WebControls.DropDownList.LoadPostData(String postDataKey, NameValueCollection postCollection) +55 System.Web.UI.WebControls.DropDownList.System.Web.UI.IPostBackDataHandler.LoadPostData(String postDataKey, NameValueCollection postCollection) +11 System.Web.UI.Page.ProcessPostData(NameValueCollection postData, Boolean fBeforeLoad) +408 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3776



버전 정보: Microsoft .NET Framework 버전:2.0.50727.42; ASP.NET 버전:2.0.50727.42

마지막 업데이트 : (7/25/2006 9:33:29 AM)

TAG : 없음



Trackback 보기 (0)
댓글 보기 (0)
댓글 쓰기



<< < 1 2 3 4 5 6 > >>