'분류 전체보기'에 해당되는 글 744건

  1. 2009.09.24 [util] easy file locker
  2. 2009.09.23 [wpf] FIle Share 파일이 열려있을때에도 딴쪽에서 읽을수 있게하기~
  3. 2009.09.22 [wpf] IIS제어 프로그램 소스
  4. 2009.09.22 [wpf] Thread를 이용하여 상태 정보 업데이트 하기
  5. 2009.09.22 [wpf] WPF에서 IIS 제어하기 1
  6. 2009.09.21 [wpf] INotifyPropertyChanged과 Observable Collection을 이용한 바인딩 샘플파일
  7. 2009.09.21 [wpf] delegate 쓸때 파라미터 쓰는 메소드 만들기
  8. 2009.09.21 [wpf] Observable Collection을 이용한 바인딩 샘플
  9. 2009.09.17 [wcf] WCF 서비스 인스턴스 관리(session Mode에 관해서)
  10. 2009.09.16 [wpf] xml 만들어서 file로 쓰기 1
  11. 2009.09.16 [기타] windows 2008 에서 강력한 암호 해제 방법
  12. 2009.09.10 [wpf] MenuItem Binding걸어서 Click Event 받아오기(어느메뉴를 클릭했는지..)
  13. 2009.09.08 [기타] 윈도우 VISTA 이상 멀티부팅 이름 바꾸는법 ㅡ.ㅡ;
  14. 2009.09.04 [wpf] Regex를 이용해서 string 문자를 치환하자...
  15. 2009.08.28 [wpf] xml viewer 만들기 (treeview 이용)
  16. 2009.08.28 [wpf] load xml
  17. 2009.08.27 xp 비밀번호 초기화
  18. 2009.08.11 아빠 사줄 usb랑 인라인스케이트 부속품
  19. 2009.08.10 이문제 풀어보자 1
  20. 2009.08.10 원격제어 사이트 http://www.nqvm.com/ 1
  21. 2009.08.05 [가사] 커플 - 김용준
  22. 2009.08.04 [tekken] 일본 스티브
  23. 2009.08.04 e-book 다운로드 사이트
  24. 2009.07.31 [wcf] 파일 전송 기능 정리한거
  25. 2009.07.31 음악 무료듣기 사이트
  26. 2009.07.31 wcf설명
  27. 2009.07.29 [util] 폴더 용량 체크 프로그램
  28. 2009.07.24 크래들형 외장하드 고려해보자.........
  29. 2009.07.22 [wcf] wcf 대용량 파일전송 2
  30. 2009.07.20 dvi 3m 싱글케이블 파는곳 싸게
좋은 프로그램2009. 9. 24. 10:07
http://www.xoslab.com/index.html

파일및 폴더를 아주 간단하게 숨기고 락을 걸수있다....

딴 프리웨어보다 훨신 좋은거 같다

Posted by 동동(이재동)
wpf2009. 9. 23. 15:40

FileInfo fi = new FileInfo(path);

fi.Open(FileMode.Open, FileAccess.ReadWriteFileShare.Read);

 

이렇게 파일을 열었다고 하면,

파일을 읽기/쓰기 모드로 열고 파일 공유를 읽기로만 설정한 경우입니다.

 

이렇게 열린 파일을 다른 프로세스에서 읽을려면,

 

FileInfo fi = new FileInfo(@"D:test.txt");

fi.Open(FileMode.Open, FileAccess.Read ,FileShare.ReadWrite);

로 여시면 됩니다.

 

FileShare의 기본값은 Read 이므로 반드시 명시해 주셔야 합니다. 

 

이미 이전 프로세스에서 읽기/쓰기 모드로 열려 있는데

다음 프로세스에서 읽기 공유만 허용한다는 설정이 안 맞는 것이 됩니다.

 

FileMode.Open, (1)FileAccess.ReadWriteFileShare.Read

FileMode.Open, FileAccess.Read ,(1)FileShare.ReadWrite

*(1)이 대응 되어야 함

 

다음은 간단한 예제 입니다.

 

private void btn_Write_Click(object sender, EventArgs e)
{
            if (txt_path.Text.Trim().Length > 0)
            {
                fs = new System.IO.FileStream(txt_path.Text, FileMode.Append, FileAccess.Write, FileShare.Read);
                                
                byte[] buf = Encoding.Default.GetBytes(txt_Write.Text);
                
                fs.Write(buf, 0, buf.Length);
                
                fs.Flush();
            }
}

 

 private void btn_Read_Click(object sender, EventArgs e)
 {
            if (txt_path.Text.Trim().Length > 0)
            { 
                System.IO.FileStream tfs = File.Open(txt_path.Text, FileMode.Open, FileAccess.Read, FileShare.Write);
                
                sr = new StreamReader(tfs, Encoding.Default);
                
                txt_read.Text = sr.ReadToEnd();
            }
   }

Posted by 동동(이재동)
wpf2009. 9. 22. 17:17
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices;

namespace IISControler
{
    /// <summary>
    /// IIS Controler 
    /// 2009-09-22 jdlee
    /// </summary>

    class IISControl
    {
        string MetabasePath = "IIS://Localhost/W3SVC";

        public IISControl(string MetabasePath)
        {
            this.MetabasePath = MetabasePath;
        }

        internal void DeleteSite(string SiteName)
        {
            try
            {
                DirectoryEntry directoryEntry = new DirectoryEntry(MetabasePath + "/" + GetSiteId(SiteName));
                directoryEntry.DeleteTree();
            }
            catch (Exception)
            {                
                throw;
            }
        }

        internal void StopSite(string SiteName)
        {
            try
            {
                DirectoryEntry directoryEntry = new DirectoryEntry(MetabasePath + "/" + GetSiteId(SiteName));
                directoryEntry.Invoke("Stop", null);
            }
            catch (Exception)
            {
                
                throw;
            }
        }

        internal void StartSite(string SiteName)
        {
            try
            {
                DirectoryEntry directoryEntry = new DirectoryEntry(MetabasePath + "/" + GetSiteId(SiteName));
                directoryEntry.Invoke("Start", null);
            }
            catch (Exception)
            {
                
                throw;
            }
        }

        internal void CreateSite(string SiteId, string SiteName, string SitePath)
        {
            try
            {
                DirectoryEntry directoryEntry = new DirectoryEntry(MetabasePath);
                string className = directoryEntry.SchemaClassName.ToString();

                if (className.EndsWith("Service"))
                {
                    DirectoryEntries sites = directoryEntry.Children;
                    DirectoryEntry newSite = sites.Add(SiteId, (className.Replace("Service", "Server")));
                    newSite.Properties["ServerComment"][0] = SiteName;
                    newSite.CommitChanges();

                    DirectoryEntry newRoot;
                    newRoot = newSite.Children.Add("Root", "IIsWebVirtualDir");
                    newRoot.Properties["Path"][0] = SitePath;
                    newRoot.Properties["AccessScript"][0] = true;
                    newRoot.CommitChanges();
                }
            }
            catch (Exception)
            {
                
                throw;
            }
        }

        internal void SetSiteBinding(string SiteName, string BindingInfo)
        {
            string propertyName = "ServerBindings";

            try
            {
                DirectoryEntry directoryEntry = new DirectoryEntry(MetabasePath + "/" + GetSiteId(SiteName));

                if (directoryEntry.Properties[propertyName].Value == null)
                    directoryEntry.Properties[propertyName].Add(BindingInfo);
                else
                    directoryEntry.Properties[propertyName][0] = BindingInfo;

                directoryEntry.CommitChanges();
            }
            catch (Exception)
            {
                
                throw;
            }
        }

        internal string GetStatusInfo(string SiteName)
        {
            string Status = "Null";
            
            if (GetSiteId(SiteName) != null)
            {
                DirectoryEntry directoryEntry = new DirectoryEntry(MetabasePath + "/" + GetSiteId(SiteName));

                switch (directoryEntry.Properties["ServerState"].Value.ToString())
                {
                    case "2":
                        return Status = "Start";
                    case "4":
                        return Status = "Stop";
                    case "6":
                        return Status = "Pause";
                }
            }        
            
            return Status;
        }

        private string GetSiteId(string webSiteName)
        {
            try
            {
                DirectoryEntry root = new DirectoryEntry(MetabasePath);
                string siteid = null;

                foreach (DirectoryEntry item in root.Children)
                {
                    if (item.SchemaClassName == "IIsWebServer")
                    {
                        if (webSiteName == item.Properties["ServerComment"].Value.ToString())
                            siteid = item.Name;
                    }
                }

                if (siteid == null)
                    return null;

                return siteid;
            }
            catch (Exception)
            {
                
                throw;
            }
        }
    }
}

Posted by 동동(이재동)
wpf2009. 9. 22. 17:08
Thread를 이용해서 상태 정보를 입력해보자 이걸한 이유는 상태값을 모니터링 해야하는데

마땅히 상태정보를 변경할때 알려주는 이벤트가 없기때문에 쓰레드를 이용해서 2초에 한번씩 계속 상태정보를 뿌려준다.

Thread ServiceStatusUpdateThread;
delegate void DelegateStatusUpdate();
 private bool _active = true;


일단 머 쓰레드랑 ui변경을 위한 delegate와 계속 while문을 돌리기 위한 bool문을 선언한다.


 private void StatusUpdate()
        {
            if (ServiceStatusUpdateThread == null)
            {
                ServiceStatusUpdateThread = new Thread(new ThreadStart (UpdateServiceStatus));
                ServiceStatusUpdateThread.Start();                
            }
        }

이렇게 클래스를 생성하고 쓰레드 시작을 한다.

여기서는 UpdateServiceStatus()메소드를 쓰레드로 돌렸다.


  private void  UpdateServiceStatus()
        {
            while (_active == true)
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, new DelegateStatusUpdate(RefreshStatus));
                Thread.Sleep(2000);
            }
        }

UpdateServiceStatus에는 UI에 업데이트할 Delegate 메소드 RefreshStatus()를 입력한다.

  private void RefreshStatus()
        {
            xDataService.Text = "DataService                : " + iisControl.GetStatusInfo("DataService");
            xDataServiceForCast.Text = "DataServiceForCast       : " + iisControl.GetStatusInfo("DataServiceForCast");
            xDataServiceForManager.Text = "DataServiceForManager : " + iisControl.GetStatusInfo("DataServiceForManager");
        }

자 이제 RefershStatus()에서 본격적으로 상태값을 textBlock에 쓴다 .즉 업데이트한다...

머 이런식으로 하면 되는데 개운하지는 않다.. class라면 notifychanged나 이런걸로 하면 되는데 방법이 없나보다..



Posted by 동동(이재동)
wpf2009. 9. 22. 14:36
IIS를 제어할일이 생겨서 IIS를 제어해보았다... 박과장이 정말 어렵다고 하고 ms에 전화까지 했다던데 못한다고 했는것을

야근시간에 금방했다......ㅡ.ㅡ;;;

일다 참고했던 사이트들이다.

Active Directory 작성방법
http://www.microsoft.com/korea/technet/tcevents/itevents/mec/dev370.mspx
http://stopwebsite

http://forums.asp.net/t/1187304.aspx

.NET 환경하에서의 ADSI 프로그래밍의 개요 
http://www.egocube.pe.kr/adsi_0005.asp

iis 제어 use DirectoryService 
http://msdn.microsoft.com/en-us/library/ms525865.aspx


그리고 DirectoryEntry의 PropertyNames를 보는법이다.

foreach (string item in path.Properties.PropertyNames)            
{
                foreach (object Value in path.Properties[item])
                {
                    xResultBox.Items.Add("key = " +item +" Value = "+Value.ToString());
                }
}

이렇게 listbox에 붙여서만 밨어야했다. 아니면 디버깅사이에서 보기는 힘들었다.

구현한 소스는 첨부로 해놓아야겠다 class로 깔끔하게 묶어서 class만 부르면 언제든지 사용가능하게 만들었다.

IIS 추가,삭제,바인딩세팅,시작,정지 가 되도록 sitename만 넣으면 다 되게 했다.

1차 파일 : [#FILE|IISControler.zip|pds/200909/22/37/|mid|0|0|pds15|0#]

2차 수정은 상태업데이트를 이용하였다 다음 포스트에 쓰겠지만 상태를 계속 모니터링해야하기 때문에

상태가 변하면 알려주는 이벤트가 있으면 좋겠지만그런건 없었다...ㅠ.ㅠ

그래서 쓰레드를 이용해서 2초에 한번씩 상태를 계속 업데이트 하게 만들었다....

2차 파일 : [#FILE|IISControler_2.zip|pds/200909/22/37/|mid|0|0|pds15|0#]


Posted by 동동(이재동)
wpf2009. 9. 21. 17:47
압축을 풀면

logviewer(클라이언트)

udp 서버 폴더가 있는데


아이피를 맞추고 실행하면 된다.

CPortStatusInfo 이클래스를 보면 어떻게 썼는지 나온다.


[#FILE|GetListEvent.zip|pds/200909/21/37/|mid|0|0|pds16|0#]
Posted by 동동(이재동)
wpf2009. 9. 21. 17:32
기존 나는 delegate를 쓸때 메소드 파라미터를 주지 못했었다.


기존은 

 private delegate void DelegateSetStatus();

이런식으로 하고

this.Dispatcher.Invoke(DispatcherPriority.Normal,new DelegateSetStatusForRemove(RemovePortStatus));

이런식으로 해서 메소드에 파라미터를 줄수 가 없었다...

하지만

private delegate void DelegateSetStatus(string message);

string message= "test message";

this.Dispatcher.Invoke(new DelegateSetStatus(SetStatus), new object[] { message });

이런식으로  델리게이트  메소드에 파라미터를 줄수가 있다.. 

물론 메소드는 이렇게 되어있겠지

private void DelegateSetStatus(string message)
{
   ...
}


Posted by 동동(이재동)
wpf2009. 9. 21. 16:34
bservable Collection을 이용한 바인딩 샘플

파일>새로만들기>프로젝트
 순서로 누른다 .

 

 

 

 

 

 

 

 

 

[확인]을 눌러서 프로젝트를 생성한다.

Person 클래스 파일을 추가한다.  System.ComponetModel과 System.Collections.ObjectModel을 추가하고 다음의 코드를 완성한다.

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
 
namespace ObservableCollection
{
    public class Person : INotifyPropertyChanged 
    {
        #region INotifyPropertyChanged 멤버
 
        public event PropertyChangedEventHandler PropertyChanged;
 
        protected void OnPropertyChanged(string info)
        {
            if(PropertyChanged!=null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
 
        #endregion
 
        public Person()
        {
        }
 
        public Person(string first, string last, string town)
        {
            this.firstname = first;
            this.lastname = last;
            this.hometown = town;
        }
        public override string ToString()
        {
            return firstname.ToString();
        }
 
        private string firstname;
 
        public string FirstName
        {
            get { return firstname; }
            set { 
                firstname = value;
                OnPropertyChanged("FirstName");
            }
        }
        private string lastname;
 
        public string LastName
        {
            get { return lastname; }
            set { 
                lastname = value;
                OnPropertyChanged("LastName");
            }
 
        }
        private string hometown;
 
        public string HomeTown
        {
            get { return hometown; }
            set {
                hometown = value;
                OnPropertyChanged("HomeTown");
            }
        }
    }
 
    public class People : ObservableCollection<Person>
    {
        public People() : base()
        {
            Add(new Person("Michael", "Alexander", "Bellevue"));
            Add(new Person("Jeff", "Hay", "Redmond"));
            Add(new Person("Christina", "Lee", "Kirkland"));
            Add(new Person("Samantha", "Smith", "Seattle"));
        }
    };
}

Window1.xaml 파일을 아래와 같이 수정한다.

<Window x:Class="ObservableCollection.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Binding to a Collection"
    xmlns:local="clr-namespace:ObservableColleciton"
    SizeToContent="WidthAndHeight"
    >
 
</Window>

Window1.xaml에 리소스를 추가한다.

  <Window.Resources>
    <ObjectDataProvider x:Key="MyFriends" ObjectType="{x:Type local:People}"/>
    <Style TargetType="ListBoxItem">
      <Setter Property="FontFamily" Value="Verdana"/>
      <Setter Property="FontSize" Value="11"/>
      <Setter Property="Padding" Value="10"/>
    </Style>
    <DataTemplate x:Key="DetailTemplate">
      <Border Width="300" Height="100" Margin="20"
              BorderBrush="LightSeaGreen"  BorderThickness="3" Padding="8"
              CornerRadius="5">
        <Grid>
          <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
          </Grid.ColumnDefinitions>
          <TextBlock Grid.Row="0" Grid.Column="0" Text="First Name:"/>
          <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=FirstName}"/>
          <TextBlock Grid.Row="1" Grid.Column="0" Text="Last Name:"/>
          <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=LastName}"/>
          <TextBlock Grid.Row="2" Grid.Column="0" Text="Home Town:"/>
          <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=HomeTown}"/>
        </Grid>
      </Border>
    </DataTemplate>
  </Window.Resources>

끝으로 컨트롤을 작성한다.

  <StackPanel>
    <TextBlock FontFamily="Verdana" FontSize="11"
               Margin="5,15,0,10" FontWeight="Bold">My Friends</TextBlock>
    <ListBox Width="200" IsSynchronizedWithCurrentItem="True"
             ItemsSource="{Binding Source={StaticResource MyFriends}}"/>
    <TextBlock FontFamily="Verdana" FontSize="11"
               Margin="5,15,0,5" FontWeight="Bold">Information</TextBlock>
    <ContentControl Content="{Binding Source={StaticResource MyFriends}}"
                    ContentTemplate="{StaticResource DetailTemplate}"/>
  </StackPanel>

끝으로 실행해 본다. ... 아래와 같이 뜨면 잘한겨..


이 글과 관련있는 글을 자동검색한 결과입니다 [?]




















Posted by 동동(이재동)
wcf2009. 9. 17. 11:29
지난 11월 10일 닷넷 프레임워크 3.0이 정식 릴리스 되었다. 2.0이 발표된 지 채 1년도 안 돼 등장한 새 버전이지만 3.0은 기존 2.0에 WPF, WF, WCF, CardSpace 등이 추가되었을 뿐이다. 1.x 에서 2.0으로 변화한 것처럼 진화된 것이 아니라 2.0에 새로운 기능들이 추가된 채로 3.0이 발표되었을 뿐이다. 닷넷 프레임워크 3.0의 정식 버전이 릴리스 될 때까지 이들 기술을 습득하는 것을 미뤄온 독자들이 있다면 이젠 핑계거리가 없게 되었다.

이번 호에서는 WCF 에서 서비스 인스턴스를 관리하는 다양한 방법들을 소개하고자 한다. WCF 서비스를 프로그래밍할 때 항상 서비스의 계약(contract), 즉 인터페이스를 정의하고 이 인터페이스를 구현하는(implement) 서비스 타입을 정의해야 했다.

서비스 타입은 대개 닷넷의 클래스를 사용하기 마련이다. 서비스가 클라이언트의 요청을 처리하기 위해서는 클래스만 가지고는 아무런 일도 할 수 없다. 클래스의 인스턴스가 있어야 서비스 호출을 처리할 수 있을 것이다. 이렇게 WCF에서 서비스 타입의 인스턴스를 어떻게 생성하고 관리할 것인가에 대해 살펴보도록 하자.

때때로 새로운 것을 배우기 전에 과거의 것을 보고 정리하는 것이 도움이 되는 경우가 많다. WCF의 배경이 되는 기존 ASP.NET 웹 서비스(ASMX)와 닷넷 리모팅에서 제공하는 인스턴스 관리에 대해 간략하게 먼저 살펴보도록 하겠다. 지금부터 필자가 언급하는 내용은 대부분 독자들도 익히 아는 내용일런지 모르겠지만, 정리한다는 의미에서 읽어 보는 것도 나쁘지 않을 것이다. 그럼 기존 기술의 서비스 인스턴스 관리를 살펴보자.


ASMX의 인스턴스 관리

ASP.NET이 제공하는 XML 웹 서비스는 매우 간단한 서비스 인스턴스 모델을 가지고 있다. 클라이언트가 웹 서비스의 메소드를 호출하면 웹 서비스 클래스의 새로운 인스턴스가 생성되고 그 인스턴스의 메소드가 호출된다. 그리고 메소드 호출이 완료되면 그 인스턴스는 곧바로 버려지게 된다. 이럴 경우에 어느 때 메모리에서 인스턴스가 제거되는 가는 GC (Garbage Collector) 만이 알고 있을 것이다.

구체적인 예제는 리스트 1과 같다. 리스트 1의 웹 서비스를 호출하면 AsmxInstancing 클래스의 인스턴스가 생성되고 이 인스턴스에 대해 Echo 메소드가 호출된다. Echo 메소드가 리턴하게 되면 ASP.NET 런타임은 생성한 인스턴스에 대해 Dispose를 호출한 후에 그 인스턴스를 버린다.

리스트 1의 웹 서비스를 2회 호출했을 때, 이 코드가 생성하는 디버그 메시지의 내용은 다음과 같다.

Service Instance Created...
Echo invoked... call count = 1
Service Instance Disposing...
Service Instance Created...
Echo invoked... call count = 1
Service Instance Disposing...

매번 웹 메소드 호출마다 새로운 인스턴스가 생성되므로 _CallCount 필드의 값이 항상 0으로 초기화 됨은 매우 당연하다. Echo 메소드가 호출될 때 표시되는 호출 회수 값은 항상 1이 됨에도 유의하자.

이렇게 ASMX는 매우 간단한 서비스 인스턴스 모델만을 가지고 있다. ASMX는 항상 이러한 단일 호출(SingleCall)에 대해 고유의 인스턴스를 생성하는 인스턴스 모델을 가짐으로써 간단하면서도 다수의 호출에도 쉽게 확장 될 수 있는(scalable) 모델을 가지고 있다. 이 인스턴스 모델의 장/단점에 대해서는 추후에 좀 더 다루기로 하자.

<리스트 1> ASMX 인스턴스 예제
[WebService(Namespace = "http://simpleisbest.net/example/wcf/instancing")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class AsmxInstancing : System.Web.Services.WebService
{
    private int _CallCount = 0;

    public AsmxInstancing ()
    {
        Debug.WriteLine("Service Instance Created...");
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        Debug.WriteLine("Service Instance Disposing...");
    }

    [WebMethod]
    public string Echo(string msg)
    {
        _CallCount++;
        Debug.WriteLine("Echo invoked... call count = " + _CallCount.ToString());
        return "You send, " + msg;
    }
}


.NET Remoting 인스턴스 관리

닷넷 리모팅은 ASMX에 비해 훨씬(?) 풍부한 인스턴스 모델을 가지고 있다. 닷넷 리모팅을 한 번이라도 접해본 독자라면 누구라도(?) 알고 있으리라 생각되는 SingleCall, Singleton, Client Activated 등이 바로 그것이다.

SingleCall 은 앞에서 살펴본 ASMX의 인스턴스 모델과 동일하다. 원격 호출이 발생할 때마다 원격 객체가 새로이 생성되며 이렇게 생성된 인스턴스가 메소드 호출을 처리한다. 메소드 호출이 완료되면 그 인스턴스는 곧바로 GC의 대상이 됨은 물론이다. ASMX와 마찬가지로 서비스 클래스(리모팅에 사용하는 클래스)가 IDisposable 인터페이스를 구현하고 있으면 Dispose 메소드는 닷넷 리모팅 런타임에 의해 자동으로 호출된다.

Singleton 인스턴스 모델은 말 그대로 Singleton 패턴을 사용한다. 오로지 하나의 서비스 인스턴스만이 생성되며 클라이언트의 개수와 원격 메소드 호출 회수에 상관없이 이 하나의 인스턴스가 사용된다. 단일 서비스 인스턴스만이 사용되므로 항상 재진입(re-entrance) 문제, 동기화 문제, 상태 유지 등에 신경을 많이 써야만 하는 인스턴스 모델이다.

Singleton 인스턴스 모델에서 인스턴스가 생성되는 시점은 최초로 클라이언트가 리모팅 호출을 하는 경우이며, 생성된 인스턴스는 애플리케이션 도메인이 종료될 때까지 계속 유지됨에도 유의하자. 이 때문에 IDisposable 인터페이스의 구현은 Singleton 모델에서 큰 의미를 갖지 않는다. 아니, IDisposable 인터페이스를 구현하는 것 자체가 문제가 될 수 있다. 왜냐하면 여러 클라이언트들에 의해 하나의 인스턴스가 공유되기 때문에 한 클라이언트가 Dispose 메소드를 호출함으로써 다른 클라이언트에게 영향을 줄 수 있기 때문이다.

Client Activated Object 인스턴스 모델, 줄여서 CAO 모델은 인스턴스의 생성과 파괴 심지어 Dispose 메소드의 호출까지도 클라이언트에 의해 제어된다. CAO 인스턴스 모델에서 인스턴스의 생성 시점은 클라이언트가 new 를 호출할 때이며, 이 때 생성자(constructor)에 대한 리모팅 호출이 발생하고 서버 측에서 CAO 인스턴스가 생성되게 된다.

클라이언트가 new 키워드를 통해 생성한 객체는 물론 서버 측의 실제 객체에 대한 프록시가 될 것이다. 여러 클라이언트가 CAO 인스턴스를 생성한다면 각 클라이언트는 고유의 인스턴스를 갖게 되며, 클라이언트가 리모팅 호출을 수행할 때마다 자신의 인스턴스가 이 호출을 서비스하게 됨에 유의하자. 인스턴스의 소멸은 클라이언트가 명시적으로 Dispose를 호출하거나 서버 측의 객체 생명 주기 리스(object life-time lease)가 만료되면 객체는 GC의 대상이 되게 된다. 닷넷 리모팅의 CAO 인스턴스 모델은 리스(lease)에 대한 이해를 필요로 하므로 지면 관계상 여기서 더 이상 설명하지 않겠다.

닷넷 리모팅의 세가지 인스턴스 관리 모델은 각기 장단점을 가지고 있다. 이들의 장단점은 WCF에서 제공하는 인스턴스 모델의 장단점과 매우 비슷하므로 WCF의 인스턴스 모델에 대해 설명할 때 이야기하기로 하겠다. 그리고 닷넷 리모팅에 대한 예제는 이달의 디스켓 내의 예제 코드를 참조하기 바란다.


WCF 서비스 인스턴스 관리

ASMX와 닷넷 리모팅과 마찬가지로 WCF 역시 서비스 타입의 인스턴스들에 대한 다양한 관리 모델을 가지고 있다. 이들은 PerCall, Per-Session, Singleton 모델로서 이제부터 각 인스턴스 관리 모델을 예제와 더불어 살펴보도록 하자.

- PerCall Services
PerCall 서비스는 ASMX의 인스턴스 관리나 닷넷 리모팅의 SingleCall 모델과 동일한 인스턴스 관리 방법으로써 WCF의 디폴트 인스턴스 관리 모델이다. 즉, 클라이언트가 서비스의 메소드를 호출하여 SOAP 메시지가 서비스에 도착하면 새로운 서비스 인스턴스가 생성된다. 그리고 이 인스턴스가 SOAP 메시지를 수신하여 메소드 호출을 수행하고, 메소드가 종료되면 그 인스턴스는 GC의 대상이 되게 된다. 물론, 서비스 타입이 IDisposable 인터페이스를 구현하고 있다면 Dispose 호출이 발생하게 됨은 ASMX와 동일하다.

PerCall 모드는 디폴트이기 때문에 구체적으로 서비스에 명시하지 않아도 되지만, PerCall 임을 명시할 수 있다. 인스턴스 모드를 명시하기 위해서는 InstanceContextMode 열거자(enumberation)를 사용하면 된다. 서비스의 인스턴스 모델은 서비스의 계약(contract 혹은 interface)과는 무관한 서버 측의 구현에 대한 상세 내용이기 때문에 인터페이스에 인스턴스 모델을 밝히지 않는다. 대신 서비스의 계약을 구현하고 있는 서비스 타입에 서비스가 갖는 여러 가지 행동 방식(인스턴스 모드, 트랜잭션 등)을 명시 하기 위해 ServiceBehavior 특성(attribute)를 사용한다. 바로 ServiceBehavior 특성에 InstanceContextMode 열거자를 통해 인스턴스 모드를 명시하면 된다.

리스트 2는 PerCall 모드를 명시적으로 표현하는 서비스 구현을 보여주고 있다. 서비스 타입인 PerCallService 클래스는 ServiceBehavior 특성을 포함하고 있으며 InstanceContextMode 속성에 PerCall 을 명시하고 있다. 앞에서 언급한 바 대로 PerCall 모드가 디폴트이므로 이와 같은 특성 선언은 불필요하다. 하지만 인스턴스 모드를 선언하는 방법을 보여주기 위해 포함된 것으로 알아두자.

<리스트 2> PerCall 모드를 사용하는 서비스 구현
[ServiceContract(Namespace="http://simpleisbest.net/wcf/example/instancing")]
public interface IEchoService
{
    [OperationContract]
    string Echo(string msg);
}

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class PerCallService : IEchoService, IDisposable
{
    private int _CallCount = 0;

    public PerCallService()
    {
        Console.WriteLine("PerCallService Created...");
    }

    public void Dispose()
    {
        Console.WriteLine("PerCallService Disposing...");
    }

    public string Echo(string msg)
    {
        _CallCount++;
        Console.WriteLine("PerCallService::Echo() invoked... call count = {0}", _CallCount);
        return "You send : " + msg;
    }
}

리스트 2를 호출하는 클라이언트를 Visual Studio 2005를 사용하여 작성한 코드는 다음과 같다. Visual Studio 2005에서 WCF 클라이언트 프록시를 생성하기 위해서는 Extension for WCF, WPF 애드인을 설치 해야만 한다. 이렇게 하면 ASMX에 대한 프록시를 만드는 것과 동일한 과정을 통해 WCF 서비스에 대한 프록시 코드를 얻을 수 있다. 다음 코드의 EchoServiceClient 클래스가 바로 이 과정을 통해 생성된 클래스이다.

PerCallService.EchoServiceClient service1 = new PerCallService.EchoServiceClient();
service1.Echo(“Hello, PerCallService”);
service1.Echo(“Hello again, PerCallService”);
service1.Close();

위와 같은 클라이언트 코드를 수행하면 서비스 측에서 다음과 같은 결과를 얻을 수 있다.

PerCallService Created...
PerCallService::Echo() invoked... call count = 1
PerCallService Disposing...
PerCallService Created...
PerCallService::Echo() invoked... call count = 1
PerCallService Disposing...

예상대로 메소드 호출이 발생할 때마다 서비스 타입인 PerCallService 클래스의 인스턴스가 생성되고 메소드 호출이 발생한 후에 곧바로 Dispose 메소드가 호출되는 것을 알 수 있을 것이다. 매번 인스턴스가 생성되기 때문에 멤버 필드인 _CallCount의 값이 매번 0으로 초기화되어 호출 카운트가 매번 1임에도 주의를 하자.

이는 ASMX, 닷넷 리모팅의 SingleCall, COM+ Just-In-Time Activation의 작동 방식과 동일하다. 인스턴스가 매번 생성된다는 것은 인스턴스가 상태를 지속적으로 유지할 수 없음을 의미하고 이는 곧 서비스를 state-less 하도록 설계해야 함을 의미한다.

PerCall 인스턴스 모드가 WCF의 디폴트 인스턴스 모드인 것은 다 이유가 있다. 첫째로 가장 간단한 메커니즘으로써 WCF 런타임이 갖는 부담이 매우 적다. 매 호출마다 새로운 인스턴스를 생성하고 호출 후에 이 인스턴스를 버림으로써 인스턴스를 유지하고 추적하며 관리해야 하는 부담을 줄일 수 있기 때문이다. 대부분의 경우 매번 인스턴스를 생성하는데 소요되는 비용은 매우 작아서 그것을 유지하는 것보다 훨씬 나은 성능을 유발한다. 그리고 우리는 지금까지 ASMX, COM+ 등에서 이렇게 상태를 유지하지 않고 서비스를 작성하는 것에 이미 익숙해져 있지 않은가?

PerCall 모드의 두 번째 장점은 확장성(scalability)이다. 확장성은 클라이언트가 10에서 100, 100에서 1000, 1000에서 10000으로 늘어나더라도 서비스가 다운되거나 크게 성능 저하가 발생하지 않음을 의미한다. 매번 인스턴스를 생성하지 않고 이것을 유지하고 추적해야만 한다면 클라이언트의 숫자가 늘어남에 따라서 관리해야 할 인스턴스의 개수도 늘어나기 마련이다. 이 때문에 클라이언트의 숫자가 크게 늘어나면 서비스는 느려지거나 심지어는 다운되는 경우도 발생하곤 한다. 항상 그렇지는 않지만 PerCall 과 같은 인스턴스 모델은 이 같은 현상이 발생될 가능성을 줄여주곤 한다.

PerCall의 세 번째 장점은 서버 자원을 효율적으로 사용할 수 있도록 해준다는 것이다. 예를 들어 보자. 서비스의 인스턴스가 생성자에서 데이터베이스를 연결하고 Dispose 시점에서 데이터베이스 연결을 해제한다고 가정해 보자. PerCall 이 아닌 전통적인 클라이언트/서버 모델에서 클라이언트는 프로그램 시작과 더불어 프록시를 생성하곤 한다. 프록시는 서비스의 인스턴스 생성을 유발하며, 생성된 서비스 인스턴스는 클라이언트의 종료와 더불어 메모리에 제거되곤 한다.

이 때 클라이언트가 꾸준히 서비스를 호출한다면 모를까, 많은 시간 동안 서비스 인스턴스는 놀고 있을 것이 자명하다(사용자의 입력 시간, 쉬는 시간 등). 이런 상황이라면 데이터베이스 연결은 불필요하게 오랫동안 유지될 것이며 이는 데이터베이스 서버에 부하를 가중시키는 커다란 요인이 되곤 한다. 만약 PerCall 인스턴스 모드를 사용한다면 클라이언트의 프록시 생성과 서비스 인스턴스 생성은 아무런 관계가 없다.

실질적으로 클라이언트가 서비스 메소드를 호출할 때라야 서비스 인스턴스가 생성되고 그 인스턴스도 메소드 호출 후에는 곧바로 Dispose 되므로 아주 짧은 시간 동안만 데이터베이스 접속이 유지될 것이다. 여기에 ADO.NET의 연결 풀링이 접목되므로 데이터베이스 연결은 다른 클라이언트를 위해 재사용 될 수도 있다. 이 어찌 효율적이라 아니할 수 있는가?

필자의 경험에 비춰볼 때 ASMX 이건 닷넷 리모팅 이건 COM+ 이건 PerCall 류의 인스턴스 관리 방법은 대부분 문제를 일으키지 않았으며 만족할만한 성능을 과시하곤 했다. 달리 마이크로소프트에서 이러한 인스턴스 관리 방법을 권장하는 것이 아니다. 그만한 이유가 있기 때문이다. WCF 역시 지난 기술들(ASMX, 닷넷 리모팅, COM+)과 마찬가지로 동등한 인스턴스 관리 모델로서 PerCall 모드를 지원하며 이것을 디폴트로 삼고 있다.

- PerSession 서비스
PerSession 인스턴스 모드는 다소 생소해 보이지만, 닷넷 리모팅의 CAO와 매우 흡사한 인스턴스 관리 방법이다. PerSession 인스턴스 모드를 이해하기 위해 먼저 정확히 해두어야 할 것은 세션의 개념이다. WCF에서 Session은 ASP.NET 의 세션이나 TCP의 세션과는 전혀 다른 의미를 갖는다. WCF에서 하나의 세션이라 함은 서비스와 연결된 하나의 프록시를 말한다. 하나의 클라이언트에서 2개의 프록시를 생성했다면 그 클라이언트는 2개의 WCF 세션을 갖는 것이다. 세션은 프록시를 생성함으로써 생성되고 프록시가 Close 될 때 세션 역시 닫힌다.

PerSession 인스턴스 모드는 세션이 유지되는 동안 서비스 인스턴스 역시 지속되는 인스턴스 모드이다. 세션이 지속되기 위해서 WCF는 바인딩(binding)이 신뢰도(reliability)가 높을 것을 요구한다. 그 이유는 세션이 유지되기 위해서는 클라이언트와 서비스가 신뢰되는 연결, 즉 바인딩을 사용해야 하기 때문이다. 쉽게 말해서 WCF에서 서비스가 어떤 바인딩을 사용하는가에 따라서 PerSession 이 의미를 가질 수도 있고, 그렇지 않을 수도 있다는 것이다.

예를 들어, BasicHttpBinding과 같이 신뢰성을 지원하지 않는 바인딩에서 PerSession은 PerCall과 동일하게 작동한다. 하지만 WsHttpBinding이나 NetTcpBinding과 같이 신뢰성을 제공하는 바인딩을 사용하면 세션 동안 서비스 인스턴스가 유지되게 된다. 바로 이 점이 CAO와 다른 점이다. 닷넷 리모팅의 CAO는 TCP 채널을 사용하건, HTTP 채널을 사용하건 관계가 없다.

<리스트 3> PerSession 모드를 사용하는 서비스 구현
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class PerSessionService : IEchoService, IDisposable
{
    private int _CallCount = 0;

    public PerSessionService()
    {
        Console.WriteLine("PerSessionService Created...");
    }

    public void Dispose()
    {
        Console.WriteLine("PerSessionService Disposing...");
    }

    public string Echo(string msg)
    {
        _CallCount++;
        Console.WriteLine("PerSessionService::Echo() invoked... call count = {0}", _CallCount);
        return "You send : " + msg;
    }
}

PerSession 인스턴스 모드를 사용하기 위해서는 마찬가지로 ServiceBehavior 특성을 이용하면 된다. 그리고 서비스의 바인딩을 WsHttpBinding 이나 NetTcpBinding 등 신뢰성을 지원하는 바인딩을 사용한다. 리스트 3은 PerSession 모드를 사용하는 서비스 구현을 보여주고 있다. 리스트 3에 대한 클라이언트 코드와 수행 시 서비스 측의 결과는 리스트 4와 같다. 예제 코드에서 2개의 프록시를 생성했음에 유의하자. 즉, 2개의 세션을 사용했다는 말이다. 각 세션 별로 서비스 인스턴스는 하나씩 존재하게 되고 인스턴스의 멤버 필드인 _CallCount 값이 계속 유지되는 것을 알 수 있을 것이다. 또한 프록시에 대해 Close 메소드가 호출되는 시점에서 서비스 인스턴스가 제거되고 Dispose 역시 호출됨에도 눈여겨 볼 필요가 있다.

<리스트 4> PerSession 클라이언트 코드와 그 결과
PerSessionService.EchoServiceClient service21 = new PerSessionService.EchoServiceClient();
service21.Echo("Hello, PerCallService");
service21.Echo("Hello again, PerCallService");
PerSessionService.EchoServiceClient service22 = new PerSessionService.EchoServiceClient();
service22.Echo("Hello, PerCallService");
service22.Echo("Hello again, PerCallService");
service21.Close();
service22.Close();

호출 결과-------------------------------------------
PerSessionService Created...
PerSessionService::Echo() invoked... call count = 1
PerSessionService::Echo() invoked... call count = 2
PerSessionService Created...
PerSessionService::Echo() invoked... call count = 1
PerSessionService::Echo() invoked... call count = 2
PerSessionService Disposing...
PerSessionService Disposing...

때때로 클라이언트가 프록시를 Close 하지 않는 경우가 발생하곤 한다. 프로그래밍 상의 실수 이거나 어떤 이유로 클라이언트 프로그램 혹은 시스템 전체가 다운되는 경우가 대표적인 사례가 되겠다. 어찌되었건 이런 상황이 발생하면 서비스 인스턴스는 서버 상에 계속 남아 있게 된다. 이러한 문제는 닷넷 리모팅의 CAO에서도 동일하게 발생할 수 있다. WCF에서는 이처럼 서비스 인스턴스가 일정 시간 이상 호출을 받지 않으면(inactivity state) 인스턴스를 제거하는 타임 아웃 기능을 제공한다. 디폴트 타임아웃은 10분이며 이 값은 프로그램적으로나 설정 파일을 통해 변경이 가능하다.

WsHttpBinding 이나 NetTcpBinding 과 같이 ReliableSession 을 지원하는 클래스는 다음과 같은 코드를 통해 ReliableSession 기능을 활성화하면서 타임아웃을 설정할 수 있다.

WsHttpBinding binding = new WsHttpBinding();
binding.ReliableSession.Enabled = true;
binding.ReliableSession.InactivityTimeout = TimeSpan.FromMinute(5);

위 코드는 .config 파일에서 다음과 같은 표현으로써 타임아웃 설정이 가능하다. 일단 타임아웃이 발생한 후에는 어떤 서비스 호출도 예외를 유발하며, 심지어 Close 호출까지도 예외를 유발함을 잊지 말자.

<wsHttpBinding>
    <binding name="CustomBinding">
        <reliableSession inactivityTimeout="00:05:00" enabled="true"/>
    </binding>
</wsHttpBinding>

이외에도 PerSession 모드는 인스턴스가 세션 내에서 유지되므로 여러 클라이언트에 의해 세션 인스턴스가 공유되도록 할 수도 있다. 이러한 내용들은 지면 관계 상 여기서 모두 다룰 수 없음을 독자들에게 사과하는 바이다. 다음에 기회가 있다면 상세히 알아볼 것을 약속하는 바이다.

이제 PerSession 모드의 장/단점에 대해 살펴보도록 하자. PerSession 모드의 최대 장점은 인스턴스가 세션 동안 상태를 유지한다는 것이다. 얼핏 머리를 스치는 것이 로그온 정보, 사용자 정보 등등을 인스턴스 내에 기록해 두고 싶다는 생각이 들지 않는가? 클라이언트가 구동되면서 서비스를 최초로 호출 함으로써 인스턴스가 생성되므로 인스턴스 생성자에서 필요한 정보를 모두 멤버 필드에 기록해 두고 이후의 메소드 호출에서 기록해 둔 정보를 재사용하는 것이다. ASP.NET 이나 ASP에서 유용하게 써먹었던 방법일 것이다.

PerSession 모드의 또 다른 유용한 사용처는 서비스 인스턴스를 생성하는 데 오랜 시간이 소요되는 경우이다. 예를 들어 서비스가 또 다른 원격 서버에 소켓(socket) 데이터를 전송해야 하거나 시리얼 포트 등을 통해 하드웨어를 액세스해야 한다면 PerCall은 매 호출마다 소켓 연결 혹은 하드웨어적인 접속 과정을 거쳐야 할 것이므로 매우 효율적이지 못할 것은 자명하다. 이 때 PerSession 은 매우 유용한 인스턴스 모드로서 대두될 것이다.

하지만 PerSession 모드는 세션의 개수가 늘어감에 따라 효율이 떨어지기 마련이다. 세션이 많으면 많을수록 WCF 런타임이 유지/추적/관리해야 할 인스턴스가 늘어나기 때문에 일반적으로 확장성이 떨어지는 경우가 많다. 또한 PerCall 에서 설명한 바 대로 불필요한 서버 자원의 낭비가 발생할 수도 있다. 따라서 PerSession 인스턴스 모드를 선택할 때는 상당한 주의가 필요하다.

이달의 디스켓 :
 


WCF 서비스 인스턴스 관리
Single 서비스

Single 모드는 닷넷 리모팅의 Singleton과 매우 비슷한 인스턴스 모드이다. 즉, 서비스 인스턴스는 오직 하나의 인스턴스만이 생성되며 모든 클라이언트의 서비스 메소드 호출을 하나의 인스턴스가 처리하게 된다. Instance ContextMode 열거자의 값 중 Single 값을 다음과 같이 사용하면 Single 모드가 사용되게 된다.

[ServiceBehavior(InstanceContextMode = Instance ContextMode.Single)]
public class SingleService : IEchoService, IDisposable
{ …… }

Single 모드에서 생성될 유일한 인스턴스는 자동으로 WCF 런타임에 의해 생성될 수도 있고, 직접 미리 생성해 놓은 인스턴스를 사용할 수도 있다. 이러한 옵션은 서비스 호스트를 생성할 때 선택할 수 있다. 다음과 같이 서비스 호스트를 생성할 때 서비스 타입을 명시하는 경우에는 최초의 클라이언트 호출이 발생할 때 인스턴스가 생성되고 그 인스턴스가 모든 클라이언트 호출을 처리하게 된다.

ServiceHost host = new ServiceHost(typeof(SingleService),
    new Uri("http://localhost:8083/wcf/instancing/single"));

서비스 호스트를 구현하는 ServiceHost 클래스의 생성자 중 서비스 타입이 아닌 인스턴스를 매개변수로 취하는 생성자가 존재한다. 이 생성자를 사용하면 미리 만들어 놓은 인스턴스를 Single 모드의 서비스 인스턴스로 사용할 수도 있다. 다음과 같이 말이다.

SingleService instance = new SingleService();
// 생성한 인스턴스에 대해 property 혹은 method 호출을 통해 초기화 한다.
ServiceHost host = new ServiceHost(instance, new Uri("http://localhost:8083/wcf/instancing/single"));

닷넷 리모팅의 Singleton에 비해 WCF의 Single 모드가 갖는 유연성이라 할 수 있겠다. 이외에도 WCF의 Single 모드는 생성된 Single 모드의 인스턴스를 액세스할 수 있는 속성 역시 제공한다. ServiceHost 클래스의 Singleton Instance 속성이 바로 그것으로써 서비스 호스트 클래스에 접근할 수 있다면 곧 Single 모드의 서비스 인스턴스에도 접근할 수 있다.

Single 모드는 PerSession 와 달리 특정 바인딩을 요구하지 않으므로 가장 기초적인 BasicHttpBinding 을 사용할 수 있음을 알아두자. Single 모드에 대한 구체적인 코드는 지면 관계상 생략한다. 실제 코드는 이 달의 디스켓의 내용을 참고하도록 하자.

Throttling
인스턴스 관리 방법과는 좀 거리가 있지만 생성되는 서비스 인스턴스의 개수를 제어하는 방법이 바로 쓰로틀링(throttling) 이다. 일반적으로 쓰로틀링은 CPU 혹은 메모리, 클라이언트 접속 개수가 일정 수준 이상으로 사용되는 것을 막기 위해 사용되는 서버 측 기법이다. 쓰로틀링을 통해 서버에 과부하가 걸리는 것을 막거나 DoS(Denial of Service)와 같은 해킹 공격을 막기 위해 사용된다.

WCF 역시 Max Concurrent Sessions, Max Concurrent Calls, Max Instances 의 세가지 방법을 통해 쓰로틀링을 지원하고 있다. Max Concurrent Sessions은 서비스에 접속하는 클라이언트의 세션 개수를 제한하고 Max Concurrent Calls는 모든 서비스 인스턴스를 통틀어 동시에 호출되는 개수를 제한하고 있다. 마지막으로 Max Instances는 말 그대로 생성되는 서비스 인스턴스의 개수를 제한한다. 디폴트 쓰로틀링 설정은 제한이 없도록 설정되어 있다.

쓰로틀링은 서비스 타입별로 설정하고 적용된다. 일단 쓰로틀링이 제한하는 최대 임계치에 도달하면 클라이언트의 호출은 큐에 삽입되게 된다. 그리고 WCF 런타임은 쓰로틀링의 임계치를 넘기지 않는 수준에서 순차적으로 큐에서 클라이언트 요청을 꺼내어 서비스를 처리하게 된다.

PerCall 인스턴스 모드에서 동시 호출의 개수는 서비스 인스턴스의 개수와 동일하다. 앞에서 필자의 설명을 잘 이해했다면 방금 설명 역시 쉽게 이해할 것이다. 따라서 PerCall 모드를 사용하는 서비스는 Max Concurrent Calls 값과 Max Instances 값 중 작은 값에 대해 동시 호출을 허용하게 된다.

PerSession 인스턴스 모드에서 클라이언트들의 전체 프록시 개수가 세션의 개수와 동일하고 각 세션마다 인스턴스가 생성되므로 Max Concurrent Sessions가 제한하는 것과 Max Instances가 제한하는 것이 같다. 따라서 Max Concurrent Session 값과 Max Instances 값 중 작은 것이 실질적으로 쓰로틀링에 의해 클라이언트 요청이 제한될 것이다.

WCF의 쓰로틀링은 프로그램적으로 혹은 설정 파일에 의해 설정될 수 있다. 프로그램적으로 쓰로틀링을 설정하기 위해서는 ServiceThrottlingBehavior 클래스를 통해 다음과 같이 설정할 수 있다.

ServiceHost host1 = new ServiceHost(typeof(PerCallService), new Uri("http://localhost:8083/wcf/instancing/percall"));
ServiceThrottlingBehavior behavior = new ServiceThrottling
Behavior();
behavior.MaxConcurrentCalls = 1;
behavior.MaxConcurrentInstances = 1;
behavior.MaxConcurrentSessions = 1;
host1.Description.Behaviors.Add(behavior);
host1.Open();

설정 파일을 사용하는 경우 다음과 같이 behavior를 설정하고 서비스에서 이 behavior 설정을 참조 하면 된다.

<system.serviceModel>
    <services>
        <service name="WCFService.PerCallService" behaviorConfiguration="InstancingTest">
            <endpoint contract="WCFService.IEchoService" binding="basicHttpBinding"/>
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="InstancingTest">
                <serviceThrottling maxConcurrentSessions="5"
                    maxConcurrentInstances="5"
                    maxConcurrentCalls="5"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

WCF는 PerCall, PerSession, Single 의 세가지 인스턴스 모드를 지원하며 각기 인스턴스를 생성하고 유지/추적/관리하는 독특한 특징을 가지고 있다. 이들은 모두 제각기 특성을 가지며 장/단점을 가지고 있다. 일반적으로는 PerCall 모드를 사용하는 것이 좋지만 항상 그렇지는 않다. 각 인스턴스 모드의 특성과 장단점을 잘 파악하고 서비스의 특성에 맞추어 인스턴스 모드를 선택해야 할 것이다. 이를 위해 POC(Proof of Concept) 작업이나 파일럿 프로젝트에서 어떤 인스턴스 모드를 선택할지 신중히 검토해야만 한다. 대개 이러한 과정을 거치지 않기 때문에 실제 프로젝트에서 어려움을 겪는 경우가 많다.

이번 칼럼에서 다룬 WCF의 인스턴스 관리 방법 외에도 WCF는 세션을 두 클라이언트가 공유하거나(Shared Session), 클라이언트측 프록시를 복사하는(duplicating proxy) 기법을 제공하여 다양한 기법으로 서비스 인스턴스와 세션을 제어하는 방법도 제공한다. 지면 관계상 이들을 모두 다루지 못한 점이 아쉽지만 필자의 블로그나 마소 칼럼을 통해 다시 다룰 것을 독자들에게 약속한다.

출처: http://www.shblitz.net/1036

'wcf' 카테고리의 다른 글

[wcf] c#에서 프로시저 실행하기  (0) 2011.05.31
[WCF] WCF REST service project 만드는법  (0) 2011.05.17
[wcf] 파일 전송 기능 정리한거  (0) 2009.07.31
wcf설명  (0) 2009.07.31
[wcf] wcf 대용량 파일전송 2  (0) 2009.07.22
Posted by 동동(이재동)
wpf2009. 9. 16. 16:21
savefilepath = 파일경로와이름


            StreamWriter sw = new StreamWriter(SaveFilePath, false, System.Text.Encoding.UTF8);
            XmlDocument doc = new XmlDocument();            
            XmlWriter xw = XmlWriter.Create(sw);
            xw.WriteStartDocument();
            xw.WriteStartElement("WindowsInfo");
            xw.WriteElementString("Width", this.ActualWidth.ToString());
            xw.WriteElementString("Height", this.ActualHeight.ToString());
            xw.WriteElementString("Left", this.Left.ToString());
            xw.WriteElementString("Top", this.Top.ToString());
            xw.WriteElementString("WindowState", this.WindowState.ToString());            
            xw.WriteEndElement();
            xw.WriteEndDocument();
            xw.Flush();
            xw.Close();
Posted by 동동(이재동)
기타2009. 9. 16. 11:20
암호 복잡성 만족 조건 해제 방법_
1. 로컬 그룹 정책 편집기를 엽니다. (제어판-> 관리도구 or Win키+R->gpedit.msc 입력 후 엔터
2. 로컬 컴퓨터 정책 -> 컴퓨터 구성 -> Windows 설정 -> 보안설정 -> 계정 정책 -> 보안 정책
3. 암호는 복잡성을 만족해야 함 -> 해제. (해당 항목 더블클릭 후 사용안함 으로 설정) 

Posted by 동동(이재동)
wpf2009. 9. 10. 20:19
일단 제멀에

  <MenuItem Header="Window" ItemsSource="{Binding}" x:Name="xWindowSelecter" />     

이런식으로 binding을 걸고 xName을 설정하였다.


  xWindowSelecter.Click += new RoutedEventHandler(xWindowSelecter_Click);

이렇게 click event를 연결한뒤

void xWindowSelecter_Click(object sender, RoutedEventArgs e)
        {   
            MenuItem selectMenuItem = e.OriginalSource as MenuItem;
            var selectedItem = selectMenuItem.Header as WindowCollection;
            if (selectedItem != null)
                SetZindexWindow(selectedItem.id);           
        }

이렇게 MenuItem으로 e.OrignalSource를 반환한후 header값을 이용하여 다시한번 원래 WindowCollection을 바꾸었다

이렇게 하니까 잘됨 

Posted by 동동(이재동)
기타2009. 9. 8. 09:01
BCEDIT로 LIST를 보고 {NTLDR} 이부분을 바꾸면 된다.

수정은 이렇게...

 bcdedit /set {ntldr} description "Windows XP Professional"
Posted by 동동(이재동)
wpf2009. 9. 4. 17:59
string의 substring이나 replace로는 문자 치환이나 검색에 한계가 있다.

그래서 Regex를 이용해서 보다 고급적이게 문자를 control할수 있는것이다...

자세한건 더 검색해보고 공부하자.... 아직 갈길이 멀구나.....


http://blog.naver.com/myheredity/130041647197
Posted by 동동(이재동)
wpf2009. 8. 28. 11:17
<Window x:Class="XPathVisualizer.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:xmlstack="clr-namespace:System.Xml;assembly=System.Xml"
    Title="XPath Visualizer">
  <Window.Resources>
    <SolidColorBrush Color="Blue" x:Key="xmlValueBrush"/>
    <SolidColorBrush Color="Red" x:Key="xmAttributeBrush"/>
    <SolidColorBrush Color="DarkMagenta" x:Key="xmlTagBrush"/>
    <SolidColorBrush Color="Blue" x:Key="xmlMarkBrush"/>
    <DataTemplate x:Key="attributeTemplate">
      <StackPanel Orientation="Horizontal" Margin="3,0,0,0" HorizontalAlignment="Center">
        <TextBlock Text="{Binding Path=Name}" Foreground="{StaticResource xmAttributeBrush}"/>
        <TextBlock Text="=&quot;" Foreground="{StaticResource xmlMarkBrush}"/>
        <TextBlock Text="{Binding Path=Value}" Foreground="{StaticResource xmlValueBrush}"/>
        <TextBlock Text="&quot;" Foreground="{StaticResource xmlMarkBrush}"/>
      </StackPanel>
    </DataTemplate>

    <HierarchicalDataTemplate x:Key="treeViewTemplate" ItemsSource="{Binding XPath=child::node()}">
      <StackPanel Orientation="Horizontal" Margin="3,0,0,0" HorizontalAlignment="Center">
        <TextBlock Text="&lt;" HorizontalAlignment="Center" Foreground="{StaticResource xmlMarkBrush}" x:Name="startTag"/>
        <TextBlock
            Text="{Binding Path=Name}"
            Margin="0"
            HorizontalAlignment="Center"
            x:Name="xmlTag"
            Foreground="{StaticResource xmlTagBrush}"/>
        <ItemsControl
            ItemTemplate="{StaticResource attributeTemplate}"
            ItemsSource="{Binding Path=Attributes}"
            HorizontalAlignment="Center">
          <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
              <StackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
          </ItemsControl.ItemsPanel>
        </ItemsControl>
        <TextBlock Text="&gt;" HorizontalAlignment="Center" Foreground="{StaticResource xmlMarkBrush}" x:Name="endTag"/>
      </StackPanel>
      <HierarchicalDataTemplate.Triggers>
        <DataTrigger Binding="{Binding NodeType}">
          <DataTrigger.Value>
            <xmlstack:XmlNodeType>Text</xmlstack:XmlNodeType>
          </DataTrigger.Value>
          <Setter Property="Text" Value="{Binding InnerText}" TargetName="xmlTag"/>
          <Setter Property="Foreground" Value="Black" TargetName="xmlTag"/>
          <Setter Property="Visibility" Value="Collapsed" TargetName="startTag"/>
          <Setter Property="Visibility" Value="Collapsed" TargetName="endTag"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding HasChildNodes}" Value="False">
          <Setter Property="Text" Value="/&gt;" TargetName="endTag"/>
        </DataTrigger>
      </HierarchicalDataTemplate.Triggers>
    </HierarchicalDataTemplate>
  </Window.Resources>
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <TextBox Name="xmlPathTextBox" Grid.Row="0" Grid.Column="0" Margin="3"/>
    <Button Margin="3" Content="Browse..." Click="BrowseXmlFile" Grid.Row="0" Grid.Column="1"/>
    <TreeView Grid.Row="2" Grid.ColumnSpan="2" Name="xmlTree" ItemTemplate="{StaticResource treeViewTemplate}">
      <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
          <Setter Property="IsExpanded" Value="True"/>
        </Style>
      </TreeView.ItemContainerStyle>
    </TreeView>
  </Grid>
</Window>

private void BrowseXmlFile(Object sender, RoutedEventArgs e)
{
    Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
    dlg.CheckFileExists = true;
    dlg.Filter = "xml files (*.xml)|*.xml|all files(*.*)|*.*";
    dlg.Multiselect = false;
    if (dlg.ShowDialog() == true)
    {
        try
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(dlg.FileName);
            XmlDataProvider provider = new XmlDataProvider();
            provider.Document = doc;
            Binding binding = new Binding();
            binding.Source = provider;
            binding.XPath = "child::node()";
            xmlTree.SetBinding(TreeView.ItemsSourceProperty, binding);
        }
        catch (XmlException)
        {
            MessageBox.Show("Xml is invalid");
        }
    }
}

Posted by 동동(이재동)
wpf2009. 8. 28. 11:16
Loading an XML Document from a File or a String

I just got stuck on something, and it was one of those "in your face" type of solutions that my friend Jeff Julian had to help me with.

I have a file called c:\temp.xml.

In C# I was trying to load this into a XmlDocument. Easy enough.

XmlDocument xml = new XmlDocument();
xml.Load("c:\temp.xml");

Of course the values aren't hard coded, but for the point this works fine.

Here was my problem. I had the contents of c:\temp.xml already loaded in as a string called xmlContents. So I was trying to

xml.Load(xmlContents);

And I was getting an "Invalid URI" error.

The solution.

xml.LoadXml(xmlContents);


출처 : http://weblogs.asp.net/scottcate/archive/2006/11/13/Loading-an-XML-Document-from-a-File-or-a-String.aspx

Posted by 동동(이재동)
기타2009. 8. 27. 14:56
WindowsXP: 부팅→F5/F8→3.안전모드/명령프롬프트→C:\에서 co
py c:\windows\repair\SAM  c:\windows\system32\config\SAM→덧붙여쓰기→이후재부팅
하면 비밀번호초기화
Posted by 동동(이재동)
기타2009. 8. 11. 20:05
세상사는 이야기2009. 8. 10. 10:02
This is a mathematical challenge, and it's been said that:

If you're an engineer, you should be able to solve it in (under) three minutes,
If you're an architect, in three hours;
If you're a doctor, in six hours;
If you're an accountant, in three months and
If you're a lawyer, probably never.

What is the missing number in this logical series?
1, 2, 6, 42, 1806, ____???

The answer is the password to open the spreadsheet that is 
attached to this email. If you figure it out, open the 
spreadsheet, type your name in, save it and resend it to 
your friends.
 

찬우씨는 보니까 풀더라 ㅋㅋ
Posted by 동동(이재동)
좋은사이트2009. 8. 10. 09:12
http://www.nqvm.com/


무료 버전이 있으므로 한번 사용해보자 ㅋㅋ 
Posted by 동동(이재동)
노래2009. 8. 5. 09:21
이젠 고백할래 baby
나만의 공주 you're my lady
내 사랑 그대에게 주고 싶은 맘
아이스크림 먹을까요
초콜릿이 더 좋을까요
그대 좋아하는 건 다 주고 싶어요

슬픈얼굴도 이젠 
환하게 웃게 할게요
그대여 결혼할까요 시작해볼까요
그댈 위한 나의 special life

우리 결혼해요
우리 사랑해요
우리 행복해요

사랑의 주문을 외워
사랑해 그댈 사랑해
이토록 벅찬 기분

저 하늘을 날아 올라
그대와 둘이서 훨훨~
믿어줄 수 있나요
사랑해요 사랑해요
그대는 나의 첫사랑

이태원 골목 기억하죠
설레임 가득한 첫키스
소중했던 행복했던 우리 이야기
지금 이순간 그대 

예쁜 얼굴의 미소가 번져요
기도할게요 지켜줄게요
그댈 위한 나의 special life

우리 결혼해요
우리 사랑해요
우리 행복해요

사랑의 주문을 외워
사랑해 그댈 사랑해
이토록 벅찬 기분

저 하늘을 날아 올라
그대와 둘이서 훨훨~
믿어줄 수 있나요
사랑해요 사랑해요
그대는 나의 첫사랑

나는 그댈 좋아해요
너무 너무 좋아요
나도 그댈 좋아해요
너무 너무 좋아요 (사랑해~)

you're so beautiful
you're so wonderful
you're so joyful
사랑의 주문을 외워
사랑해 그댈 사랑해
이토록 벅찬 기분

저 하늘을 날아올라
그대와 둘이서 훨훨~
믿어줄 수 있나요
사랑해요 사랑해요
그대는 나의 첫사랑

'노래' 카테고리의 다른 글

달콤한 노래 모음  (0) 2010.07.15
이지혜 -곰돌이  (0) 2010.07.15
음악 무료듣기 사이트  (0) 2009.07.31
[노래] 민경 - 우린 안어울려요  (0) 2009.05.18
내가 좋아하는 노래들 모음  (0) 2009.03.02
Posted by 동동(이재동)
기타2009. 8. 4. 10:10

'기타' 카테고리의 다른 글

xp 비밀번호 초기화  (0) 2009.08.27
아빠 사줄 usb랑 인라인스케이트 부속품  (0) 2009.08.11
e-book 다운로드 사이트  (0) 2009.08.04
dvi 3m 싱글케이블 파는곳 싸게  (0) 2009.07.20
시간동기화 site  (0) 2009.05.28
Posted by 동동(이재동)
기타2009. 8. 4. 09:22

'기타' 카테고리의 다른 글

아빠 사줄 usb랑 인라인스케이트 부속품  (0) 2009.08.11
[tekken] 일본 스티브  (0) 2009.08.04
dvi 3m 싱글케이블 파는곳 싸게  (0) 2009.07.20
시간동기화 site  (0) 2009.05.28
vmware에서 network 설정.  (0) 2009.05.28
Posted by 동동(이재동)
wcf2009. 7. 31. 18:05
파일 전송 기능 정리 파일

Posted by 동동(이재동)
노래2009. 7. 31. 13:47
http://zagia.com/music

싸이월드와 연동이지만 편하다 ㅋㅋ

'노래' 카테고리의 다른 글

이지혜 -곰돌이  (0) 2010.07.15
[가사] 커플 - 김용준  (0) 2009.08.05
[노래] 민경 - 우린 안어울려요  (0) 2009.05.18
내가 좋아하는 노래들 모음  (0) 2009.03.02
Alicia Keys_If I Ain't Got You  (0) 2007.08.24
Posted by 동동(이재동)
wcf2009. 7. 31. 11:05
Posted by 동동(이재동)
좋은 프로그램2009. 7. 29. 16:50
폴더 용량 체크 프로그램

그래프로 보여준다.

마치 시간표처럼

[#FILE|folder_size_check.exe|pds/200907/29/37/|mid|0|0|pds13|0#]
Posted by 동동(이재동)
세상사는 이야기2009. 7. 24. 13:10
요즘 외장하드가 용량이 모자라다.......

이럴바에는 노트북용 외장하드를 사는게 아니라 크래들용을 사는게 낫지 않을까 생각해본다.... 원하는 외장하드를 끼웠다 말았다.

이게 더 나을지도 모르고 모르겠다...

아님 그냥 노트북용 외장하드를 사는게 맞을지? 나중을 위해서라면 크래들용이 나을듯? 근데 외부전원을 공급해줘야하기때문에

멀티탭도 사야한다. 그리고 크래들 가격은 4만원정도?

하지만 순수하드만 사기때문에 그리고 3.5 인치 하드를 사기때문에 좋을수도 있겠다.

네이버 검색해서 

디지털존 크래들

이렇게 쳐보자.
Posted by 동동(이재동)
wcf2009. 7. 22. 14:49

1부에서 한거 이외에


<requestLimits maxAllowedContentLength="52428800"/>

이부분을 바꾸어 주어야한다.

자세한 참고사항은 


여기에서 보면 된다

밊은 퍼온글이다.

IIS Connection Timeout 변경

IIS 연결 타임 아웃 설정을 바꾸어 주어야 합니다. 기본 설정은 2분이기 때문에 업로드 시간이 2분이 넘어가는 큰 파일들은 중간에 오류를 일으키게 됩니다. 인트라넷의 속도를 고려하셔서 목표로 하시는 제한 크기의 파일이 안전하게 업로드 될 수 있는 시간으로 설정하시면 됩니다. 이 설정은 IIS 관리자에서 사이트를 선택하시고 Advanced Settings 에서 설정하실 수 있습니다. (IIS 7.0기준)

image

LAYOUT 폴더의 ExecutionTimeout 값의 변경

%HomeDrive%\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\LAYOUTS\Web.config 파일을 수정합니다. 

<location path="upload.aspx">

   <system.web>

     <httpRuntime maxRequestLength="2097151" />  이 라인을

     <httpRuntime executionTimeout="999999" maxRequestLength="2097151" /> 로 바꿉니다.

   </system.web>

</location>

maxRequestLength 에 대한 설명은 http://msdn.microsoft.com/en-us/library/e1f13641.aspx 를 참고 바랍니다.

각 웹어플리케이션의 ExecutionTimeout 값의 변경

%HomeDrive%\Inetpub\wwwroot\wss\VirtualDirectories\VirtualDirectoryFolder 에서

<httpRuntime maxRequestLength="51200" /> 라인을

<httpRuntime executionTimeout="999999" maxRequestLength="51200" /> 로 바꿉니다.

참고) 여기서 maxRequestLength 의 51200 은 50* 1024 즉 50 MB 를 뜻하는 것입니다. 이 값을 50MB 로 놔둬도 아래의 나머지 세팅을 해 주면 문서 라이브러리에 대용량 파일 업로드는 문제가 없지만 공지사항이나 토론 같은 리스트의 첨부는 여전히 50MB 을 넘을 수 없습니다. 따라서 리스트 첨부로 큰 파일을 올리고자 할 때에는 이 값을 늘려 주어야 합니다. 예를 들어 리스트 첨부를 300MB 까지 허용한다면 300 * 1024 = 307200 을 세팅해 주면 됩니다.

Windows 2008 /IIS7 환경의 경우 추가 요소

각 웹 어플리케이션의 폴더에서 %HomeDrive%\Inetpub\wwwroot\wss\VirtualDirectories\VirtualDirectoryFolder Web.config 파일에 아래 부분을 추가합니다.

<system.webServer>

  <security>

    <requestFiltering>

      <requestLimits maxAllowedContentLength="52428800"/>

    </requestFiltering>

  </security>

</system.webServer>

52428800 은 50 MB 입니다. 이 값은 업로드를 허용할 최대 크기보다 약간 더 크게 설정되어야 합니다. 예를 들어 한도가 300MB 로 하고 싶다면 301*1024*1024 = 315621376 정도로 설정하시면 됩니다.

Posted by 동동(이재동)
기타2009. 7. 20. 16:11

'기타' 카테고리의 다른 글

[tekken] 일본 스티브  (0) 2009.08.04
e-book 다운로드 사이트  (0) 2009.08.04
시간동기화 site  (0) 2009.05.28
vmware에서 network 설정.  (0) 2009.05.28
[사이트] 옷이쁜곳 쇼핑사이트  (0) 2009.05.19
Posted by 동동(이재동)