'C#'에 해당되는 글 23건

  1. 2011.01.06 C#, ASP.NET 웹서비스에서 DataTable 직렬화 문제
  2. 2010.12.14 C# 사용자 정의 클래스를 이용한 웹 서비스 구현
  3. 2010.11.05 ASP.NET Connection Pool
  4. 2010.10.05 C# 일관성 없는 액세스 가능성 (1)
  5. 2010.08.06 C# OpenFileDialog 필터 적용
  6. 2010.08.05 C# DataGridView 컬럼순서 변경
  7. 2010.08.05 C# 트랜잭션 처리 (2)
2011.01.06 17:08

C#, ASP.NET 웹서비스에서 DataTable 직렬화 문제

.NET 프레임워크에서 웹서비스 사용에서 인터페이스로 DataTable을 사용하려다 보면 직렬화 문제가 발행한다.

오류 내용은 "DataTable을 직렬화할 수 없습니다. DataTable 이름이 설정되지 않았습니다."

말 그대로 DataTable 이름이 설정되지 않아 발생하는 문제이다.
해결 방법은 DataTable의 TableName 프로퍼티에 이름을 설정해주면 된다.

방법

DataTable tables = .......;
tables.TableName = "tableName"
Trackback 0 Comment 0
2010.12.14 19:34

C# 사용자 정의 클래스를 이용한 웹 서비스 구현

웹 서비스를 구현하다 보면 사용자 정의 클래스를 이용해 웹 서비스 통신해야 하는 경우 또는 하고 싶은(?) 경우가 있다. 이 경우에는 한가지만 제외하면 굉장히 간단하다.

사용자 정의 클래스를 이용한 웹 서비스 구현 과정은 다음과 같다.
1. 웹 서비스 통신에서 사용할 사용자의 정의 클래스 구현
2. 웹 서비스에 사용자 정의 클래스 참조 추가
3. 사용자 정의 클래스를 이용하는 웹 서비스 메소드 구현
4. 웹 서비스 호출 측에서 통신에서 사용할 사용자 정의 클래스 참조 추가
5. 웹 서비스 호출 측에 웹 서비스 참조 추가
6. 웹 서비스 참조 수정

1. 웹 서비스 통신서 사용할 사용자 정의 클래스 구현
아래와 같이 클래스 라이브러리 형태의 프로젝트를 생성하고 사용자 정의 클래스를 구현한다.

namespace UserLibrary
{
    public class User
    {
        private string userName;

        private string userPassword;

        public User()
        {
        }

        public User(string userName, string userPassword)
        {
            this.userName = userName;
            this.userPassword = userPassword;
        }

        public string UserName
        {
            get { return userName; }
            set { userName = value; }
        }

        public string UserPassword
        {
            get { return userPassword; }
            set { userPassword = value; }
        }
    }
}


2. 웹 서비스에 사용자 정의 클래스 참조 추가
새로운 프로젝트를 웹 서비스 형태로 생성하고 프로젝트에 사용자 정의 클래스가 구현된 프로젝트를 참조로 추가한다.




3. 사용자 정의 클래스를 이용하는 웹 서비스 메소드 구현
아래와 같이 사용자 정의 클래스를 이용하는 메소드를 구현한다.
[WebMethod]
        public User GetNewUser(User user)
        {
            user.UserName = "New " + user.UserName;
            user.UserPassword = "New " + user.UserPassword;

            return user;
        }


4. 웹 서비스 호출 측에서 통신에서 사용할 사용자 정의 클래스 참조 추가
웹 서비스를 호출하는 쪽에서도 동일한 사용자 정의 클래스를 가져와서 참조로 추가를 한다.

5. 웹 서비스 호출 측에 웹 서비스 참조 추가
프로젝트 선택 → 서비스 참조 추가 → 팝업창에서 좌측 아래 [고급] → 좌측 아래 [웹 참조 추가]글 선택하면 아래와 같은 화면이 뜨고 URL을 입력하고 이동을 클릭하면 호출할 수 있는 웹 서비스가 뜬다. 여기에서 [참조 추가]를 하면 정상적으로 웹 서비스가 등록된다.



6. 웹 서비스 참조 수정
자~ 그럼 웹 서비스 메소드를 호출해보자. 아래와 같이 웹 서비스를 호출하는 측에서 사용자 정의 객체를 이용해서 웹 서비스를 호출해보자.

static void Main(string[] args)
        {
            localhost.Service1 ws = new WebServiceCaller.localhost.Service1();
            UserLibrary.User user = new UserLibrary.User("test user", "test password");

            Console.WriteLine("웹 서비스 호출 전");
            Console.WriteLine(user.UserName);
            Console.WriteLine(user.UserPassword);
            
            UserLibrary.User newUser = ws.GetNewUser(user);

            Console.WriteLine("웹 서비스 호출 후");
            Console.WriteLine(newUser.UserName);
            Console.WriteLine(newUser.UserPassword);

            Console.ReadLine();
        }

으잉?? 잘못된 인수가 있다는 오류와 변환할 수 없다는 오류가 뜬다.. 제대로 작성했는데..;;;


이유인 즉슨 웹 서비스 참조를 추가하면서 사용자 정의 클래스를 웹 서비스에서 제공하는 클래스로 다시 정의해버린 것이다.

툴바의 [프로젝트] → [모든 파일 표시]를 선택 후 솔류션 탐색기에서 웹 서비스의 Refence.map의 Refecence.cs 파일을 열어보자. 아래와 같이 사용자 정의 클래스가 재정의된 것을 볼 수 있다.


해결책: 재정의된 클래스 부분을 삭제하고(/// <remarks/> 부분부터 삭제해야 됨) 파일 맨위 using문에 우리가 정의한 클래스를 적어주자. 그럼 오류가 없어질 것이다.

namespace WebServiceCaller.localhost {
    using System.Diagnostics;
    using System.Web.Services;
    using System.ComponentModel;
    using System.Web.Services.Protocols;
    using System;
    using System.Xml.Serialization;

    using UserLibrary;

결과: 짜란~ 정상적으로 웹 서비스가 호출된 것을 볼 수 있다.


주의할 점: 웹 서비스를 호출하기 전에 반드시 웹 서비스를 구동 시켜야 한다.


[참조] How to Return a User Defined Object from Webservice
Trackback 0 Comment 0
2010.11.05 11:08

ASP.NET Connection Pool

커넥션 풀링에 관해 알아보겠습니다.
원래 질답란에 있던 내용인데, 일반적이지 않은 내용이어서 정리를 해서 일반적인 사용법을 알려드리겠습니다.

커넥션 풀링은 DB와의 새 연결시 많은 자원을 소모하는 데, 직접연결을 피하고, 연결된 커넥션을 자원으로서 관리를 하여 성능향상을 얻고자 하는 방법입니다.

다시 설명하면, 
풀링매니저가, 연결된 커넥션을 자원으로 관리를 하면서, 어플리케이션에서 필요로 할 때 리소스가 많이 필요한 새연결을 하지 않고, 기존 자원으로 재사용을 하고, 연결 끊기문장을 만났을 때 DB와의 실제 연결을 끊지 않고, 풀링에 반납함으로써, DB와의 연결과 끊기를 실제적으로 줄여주는 효과가 있습니다.

1) 풀링의 생성
어플리케이션에는 한개이상의 커넥션 풀링이 존재할 수 있습니다. 이 각각의 커넥션 풀링은 특정한 connection string에 관계가 있습니다.
최초에 커넥션이 닫힐 때, 특정한 connection string을 가진 커넥션 풀이 생성됩니다. 그리고 연결은 실질적으로 끊지 않습니다. (풀을 사용하던 안하던 최초엔 풀에서 커넥션을 만들지 않음)

그후 새로운 커넥션이 생성이 될 때, connection string 이 기존 풀의 connection string과 다르면, 커넥션이 닫힐 때 새로운 pool이 생성됩니다. 이때 만약 똑같은 connection string 을 사용한다면 새로운 풀이 생성되지 않고 기존의 커넥션을 이용합니다.

이를 소스로서 예를 들어보면.
SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Integrated Security=SSPI;Initial Catalog=northwind";
conn.Open();      
// Pool A 가 생성됨

SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Integrated Security=SSPI;Initial Catalog=pubs";
conn.Open();      
// Pool B 가 생성됨 (connection string이 다르다)

SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Integrated Security=SSPI;Initial Catalog=northwind";
conn.Open();      
// Pool A의 자원을 이용한다. connection string 이 Pool A와 일치.

 

여기에선 모두 3개의 connection 객체가 생성되었지만, 2개의 connection pool이 생성되었다.풀이 일단 한번 생성되면, 프로세스가 종료할 때가지 사라지지 않고 지속된다. 비어있는 풀은 최소한의 오버헤드를 야기한다.

2) 커넥션관련 추가사항
커넥션은 한번 생성되면 minimum pool size가 충족될때까지 connection 이 풀링된다.
만약 sqlconnection이 요청되면, 풀에서 사용가능한 커넥션이 얻어진다. 만약 maximum pool size에 도달하여, 사용가능한 커넥션이 없다면 풀에서 자원이 반납될 때까지 기다린다. time-out 기간까지 얻어내지 못하면, 에러가 발생한다.

3) 주의사항
반드시 connection을 사용후에는 반납을 해야한다.
반납은 close() 나 dispose()를 통해 가능하다. nothing은 할 필요는 없다.
반납을 명시적으로 하지 않게 되면, 풀에 자원반납이 되지 않는다.

4) connection  pool관련 keyword
Pooling : 기본값 'true' : 이것을 false로 하면, 풀링이 사용되지 않는다. 즉 open()시 직접 DB를 열고, close()시 닫는다.
Max Pool Size : 기본값 100 : 최대 풀링사이즈
Min Pool Size : 기본값 0 : 최소 풀링사이즈 
Connection Lifetime : 기본값 0(초) : 이것은 풀내에서 커넥션들의 lifetime이다. 

5) 사용예
보통 커넥션 스트링에 
con.ConnectionString = "data source=xxx.xxx.xxx.xxx; initial catalog=nothwinds;user id=sa;password=" 

이렇게 쓰신다면, 풀링을 사용하시는 겁니다.왜냐하면, Pooling=true 가 디폴트 값이니까요..

con.ConnectionString = "data source=xxx.xxx.xxx.xxx; initial catalog=nothwinds;user id=sa;password=, Pooling='true''" 

이것과 같은 의미입니다. 또한 Max Pool Size 속성이 디폴트값이 100 이므로 
con.ConnectionString = "data source=xxx.xxx.xxx.xxx; initial catalog=nothwinds;user id=sa;password=, Pooling='true'', Max Pool Size=100" 
이것도 같은 의미입니다.

6) 기타
퍼포먼스 카운터를 이용하면, 현재 풀의 사이즈를 실시간으로 조사할 수 있습니다.
퍼포먼스 카운터는 관리도구-> 성능 탭으로 이용합니다.

그중에서 ".NET CLR Data" performance object 를 선택하여서 보면 다음과 같은 항목을 확인 할 수 있습니다.

Counter Description
SqlClient: Current # of pooled and non pooled connections Current number of connections, pooled or not.
SqlClient: Current # pooled connections Current number of connections in all pools associated with the process.
SqlClient: Current # connection pools Current number of pools associated with the process.
SqlClient: Peak # pooled connections The highest number of connections in all pools since the process started. Note: this counter is only available when associated with a specific process instance. The _Global instance will always return 0.
SqlClient: Total # failed connects The total number of connection open attempts that have failed for any reason.

[출처] 데브피아/개발자가 알아두면 좋은 ASP.NET 지식 (connection pool)
Trackback 0 Comment 0
2010.10.05 12:41

C# 일관성 없는 액세스 가능성

클래스를 선언한 후 그 클래스를 매개변수로 사용하다 보면 아래와 같은 에러가 발생할 때가 있습니다.

오류 CS0051: 일관성 없는 액세스 가능성: 'WATRemoteControl.clsChildInfo' 매개 변수 형식이 'WATRemoteControl.frmEditChild.frmEditChild1(WATRemoteControl.clsChildInfo)' 메서드보다 액세스하기 어렵습니다.

분명히 해당 클래스를 다른 곳에서는 그냥 썼는데 여기서는 왜 에러가 발생할까?
문법적으로 문제도 없고, 특별한 점도 없어 보입니다.

해결 방법
절대 혼자서는 해결이 안될거 같아 인터넷의 힘을 빌렸습니다.^^
결론은 class  선언할때 public 으로 선언해야 합니다.

예를 들어, A 클래스를 사용하려고 하고  A 클래스가 아래와 같을 때,

namespace N
{
    class A{} 
}

A a; // 형태로 선언해서 사용하면 아무런 문제가 없는데,
func(A a);// 형태의 매개 변수로 사용하면 "일관성 없는 액세스 가능성"에러가 발생합니다.

이때는 아래처럼 선언해 주면 됩니다.

namespace N
{
    public class A{} 
}


[출처] 오류 CS0051: 일관성 없는 액세스 가능성: 매개 변수 형식이 ..메서드보다 액세스하기 어렵습니다

Trackback 0 Comment 1
2010.08.06 11:52

C# OpenFileDialog 필터 적용

C#에서 파일을 열때는 OpenFileDiaglog를 사용한다. 기본적으로 열수 있는 파일의 형식은 모든 파일이다. 하지만 특정파일만 보이게 하고 싶을 때가 있다. 이때는 OpenFileDialog에 Filter를 적용하면 된다.
사용법은
OpenFileDialog openDialog = new OpenFileDialog();
openDialog.Filter = "filter_text";

filter_text 부분에 적용하고자 하는 필터 스트링을 작성함으로써 필터의 적용이 가능하다.

필터 스트링의 형식은
Label|Extension1[[;Extension2]...[;ExtensionN]]

Label은 파일 형식을 설명하는 문자열이다.
예) 
"Word 문서"
"Excel 워크시트"
"PowerPoint 프레젠테이션"
"Office 파일"
"모든 파일"

Extention은 파일의 확장자 문자열이다. 둘 이상 사용된 경우 Extention을 세미콜론으로 구분해야 한다.
예)
"*.doc"
"*.xls;"
"*.ppt"
"*.doc;*.xls;*.ppt"
“*.*”

다음은 유효한 Filter의 전체 예이다.
Word Documents|*.doc
Excel Worksheets|*.xls
PowerPoint Presentations|*.ppt
Office Files|*.doc;*.xls;*.ppt
All Files|*.*


Trackback 0 Comment 0
2010.08.05 16:09

C# DataGridView 컬럼순서 변경

일반적으로 DataGridView의 컬럼 순서를 변경하는 방법은 디자인 모드에서 열 편집 메뉴를 이용해서 가능하다. 하지만 가끔씩 데이터 바인딩시 사용자가 지정한 순서가 아닌 순서로 변경이 되는 경우가 있다.

datagridview_name.Columns["column_name"].DisplayIndex로도 해결이 안된다.

그럴땐 데이터를 바인딩 하기전에 datagridview.AutoGenerateColumns을 false로 지정하면 된다.

이거 때문에 삽질한걸 생각하면... ㅠㅠ
Trackback 0 Comment 0
2010.08.05 09:45

C# 트랜잭션 처리

public void TransactionExample()
{
    private const string CONNECT_STR = "server=server_ip;database=db_name;user id=user_id;password=password;";
    
    private SqlConnection con = new SqlConnection(CONNECT_STR);;
    private SqlCommand cmd = new SqlCommand();

    command.Connection = con;

    try
    {
        con.Open();

        //트랜잭션 시작
        cmd.Transaction = cmd.Connection.BeginTransaction();

        //쿼리 지정
        cmd.CommandText = "Update ... SET ....";
        cmd.Parameters.Clear();

        //쿼리 실행
        cmd.ExecuteNonQuery();

        //트랜잭션 Commit
        cmd.Transaction.Commit();
    }
    catch (Exception ex)
    {
        if (cmd.Transaction != null)
        {
            //오류 발생시 Rollback
            cmd.Transaction.Rollback();
        }

        Console.WriteLine("ERROR : " + ex.Source + " - " + ex.Message);
    }
}


Trackback 0 Comment 2