2017.10.27 15:53

[준비하기]

 - VS 2017 템플릿

https://marketplace.visualstudio.com/items?itemName=NUnitDevelopers.NUnitTemplatesforVisualStudio


- 다운로드 

  https://github.com/nunit/nunit/releases/3.8


- NUnit-Gui

테스트를 진행을 위한 GUI툴

 - https://github.com/NUnitSoftware/nunit-gui/releases


[프로젝트]

1. nuget에서 nunit 설치

    - NUnit3 

    - NUnit3TestAdapter


2. 프로젝트 생성

 Test메뉴에서 NUnit Test Project 선택


3. Attribute (https://github.com/nunit/docs/wiki/Attributes)

 -  [TestFixture]: 클래스에 지정하여 해당 클래스는 테스트를 위한 클래스라는 것을 지정하기 위해 사용

 - [SetUp]: 클래스 멤버나 기타 초기화가 필요한 경우 사용

 - [Test]: 메소드에 선언되며 단위별 테스트를 위한 사용

 - [ExpectedException(typeof(exception class))]: 예상되는 exception을 테스트할 경우 사용

 - [Ignore("메시지")]: 


3. Assert

 - 단위테스트의 주요 기능 결과를 확인 하기 위해 사용되는 클래스

 - 주요기능

  - AreEqual, AreNotEqual, AssertDoublesAreEqual, AreSame, AreNotSame

  - ByVal

  - True, False

  - IsTrue, IsFalse, IsEmpty, IsNull, IsNaN

  - Greater, GreaterOrEqual, , Less, LessOrEqual, Zero

  - Pass, Fail

  - Positive, Negative

  - Null, NotNull, Zero, NotZero

  - That

  - Throws


3. 테스트 실행

 - 메뉴 > 테스트 > 실행


[NUNIT Document]

https://github.com/nunit/docs/wiki/NUnit-Documentation

Posted by CoolDragon
TAGc#, NUnit

댓글을 달아 주세요

2017.07.14 16:02

- 지정된 폴더의 파일 변화 모니터링 (생성,삭제, 리네임, 변경)

- 파일이 현재 복사가 되는지 File Lock 여부


using System;

using System.Collections.Generic;

using System.IO;

using System.Linq;

using System.Runtime.InteropServices;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;


namespace FileWatcher

{

    /// <summary>

    /// MainWindow.xaml에 대한 상호 작용 논리

    /// </summary>

    public partial class MainWindow : Window

    {

        public MainWindow()

        {

            InitializeComponent();


            Start();

        }


        System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();

        string filePath = null;


        private void Start()

        {

            System.IO.FileSystemWatcher watcher = new System.IO.FileSystemWatcher();

            watcher.Path = @"d:\watch";

            watcher.NotifyFilter = System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.DirectoryName | System.IO.NotifyFilters.Size;


            watcher.Changed += Watcher_Changed;

            watcher.Created += Watcher_Created;

            watcher.Deleted += Watcher_Deleted;

            watcher.Renamed += Watcher_Renamed;

            watcher.EnableRaisingEvents = true;


            timer.Interval = new TimeSpan(0, 0, 1);

            timer.Tick += (s, args) =>

            {

                if (!string.IsNullOrEmpty(filePath))

                {

                    if (IsFileLocked(filePath))

                        Log($"File Locked");

                    else

                    {

                        Log($"File unlocked");

                        timer.Stop();

                    }

                }

            };

        }


        private void Watcher_Renamed(object sender, System.IO.RenamedEventArgs e)

        {

            Log($"{e.ChangeType}, File: {e.FullPath}, Old File: {e.OldFullPath}");

        }


        private void Watcher_Deleted(object sender, System.IO.FileSystemEventArgs e)

        {

            Log($"{e.ChangeType}, File: {e.FullPath}");

        }


        private void Watcher_Created(object sender, System.IO.FileSystemEventArgs e)

        {

            Log($"{e.ChangeType}, File: {e.FullPath}");

            timer.Start();

        }


        private void Watcher_Changed(object sender, System.IO.FileSystemEventArgs e)

        {

            filePath = e.FullPath;

            Log($"{e.ChangeType}, File: {filePath}, Length: {new System.IO.FileInfo(filePath).Length}");

        }


        private void Timer_Tick(object sender, EventArgs e)

        {

            throw new NotImplementedException();

        }


        private void Log(string str)

        {

            this.Dispatcher.Invoke(() =>

            {

                txt.Text += str + "\r\n";

            });

        }


        const int ERROR_SHARING_VIOLATION = 32;

        const int ERROR_LOCK_VIOLATION = 33;

        private bool IsFileLocked(string file)

        {

            //check that problem is not in destination file

            if (File.Exists(file) == true)

            {

                FileStream stream = null;

                try

                {

                    stream = File.Open(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None);

                }

                catch (Exception ex2)

                {

                    //_log.WriteLog(ex2, "Error in checking whether file is locked " + file);

                    int errorCode = Marshal.GetHRForException(ex2) & ((1 << 16) - 1);

                    if ((ex2 is IOException) && (errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION))

                    {

                        return true;

                    }

                }

                finally

                {

                    if (stream != null)

                        stream.Close();

                }

            }

            return false;

        }

    }

}



Posted by CoolDragon

댓글을 달아 주세요

2017.05.16 10:22

공통

    public static class LangPack

    {

        static LangPack()

        {

            Resources = new Dictionary<Language, Dictionary<string, string>>();


            Dictionary<string, string> kr = new Dictionary<string, string>();

            kr.Add("language", "한국어");


            Dictionary<string, string> en = new Dictionary<string, string>();

            en.Add("language", "영어");


            Dictionary<string, string> ch = new Dictionary<string, string>();

            ch.Add("language", "중국어");


            Resources.Add(Language.Korean, kr);

            Resources.Add(Language.English, en);

            Resources.Add(Language.Chinese, ch);

        }


        private static Dictionary<Language, Dictionary<string, string>> Resources;


        public static string GetString(string key)

        {

            if (Resources.ContainsKey(App.SelectedLanguage))

            {

                if (Resources[App.SelectedLanguage].ContainsKey(key))

                    return Resources[App.SelectedLanguage][key];

            }


            return string.Empty;

        }

    }


컨버터

    public class LanguageConverter : IValueConverter

    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

        {

            if (parameter == null)

                return string.Empty;


            if (parameter is string)

                return LangPack.GetString((string)parameter);

            else

                return string.Empty;

        }


        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

        {

            throw new NotImplementedException();

        }

    }


Application Resource

   <Application.Resources>

        <ResourceDictionary>

            <converter:LanguageConverter x:Key="LangConverter" />

            <ObjectDataProvider x:Key="language"

                ObjectType="{x:Type lang:LangPack}"

                MethodName="GetString" >

                <ObjectDataProvider.MethodParameters>

                    <s:String>language</s:String>

                </ObjectDataProvider.MethodParameters>

            </ObjectDataProvider>

        </ResourceDictionary>

    </Application.Resources>


XAML

<Button Content="{Binding Source={StaticResource language}}" />

<Button Content="{Binding Converter={StaticResource LangConverter},  ConverterParameter=language}" />







Posted by CoolDragon

댓글을 달아 주세요

2017.04.18 10:38

Command Pattern



선언

    public class DelegateCommand : ICommand
    {
        private Action<object> _execute;
        private Predicate<object> _canExecute;

        public DelegateCommand(Action<object> execute)
               : this(execute, null)
        {
        }

        public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }

        public event EventHandler CanExecuteChanged = delegate { };

        public void Execute(object parameter)
        {
            _execute(parameter);
        }

        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }
    }


구현

        private ICommand _addCommand;
        public ICommand AddCommand
        {
            get
            {
                return _addCommand ??
                    (_addCommand = new DelegateCommand(
                        p => { 
                            // Add 로직 
                        },
                        p => { // Command 사용여부 
                                  return true; 
                        }
                    ));
            }
        }




Xaml

<Button Content="Add" Command={Binding AddCommand} />

<Window.InputBidings>
    <KeyBinding Key="A"
                       Modifiers="Control"
                       Command={Binding AddCommand} />
</Window.InputBidings>




Posted by CoolDragon

댓글을 달아 주세요

2017.04.17 16:39

WPF

if (DesignerProperties.GetIsInDesignMode(new System.Windows.DependencyObject()))

{

  // Design Time Code

}

else

{

  // Runtime Code

}


WindowPhone, Silverlight

if (DesignerProperties.IsInDesignTool)

{

  // Design Time Code

}

else

{

  // Runtime Code

}


Windows Store

if (DesignerProperties.DesignModeEnabled)

{

  // Design Time Code

}

else

{

  // Runtime Code

}






Posted by CoolDragon

댓글을 달아 주세요

2017.04.17 14:39
    public class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        protected virtual void RaisePropertyChangedEvent([CallerMemberName] string propertyName = null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        protected virtual void SetProperty<T>(ref T member, T val, [CallerMemberName] string propertyName = null)
        {
            if (object.Equals(member, val)) return;

            member = val;
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }


    
    public class ViewModelBase : ObservableObject
    {
        public virtual bool IsInDesignMode()
        {
#if WINDOWS_PHONE_APP
            if (DesignerProperties.IsInDesignTool)
            {
              return true;
            }
            else
            {
              return false;
            }
#else
            if (DesignerProperties.GetIsInDesignMode(new System.Windows.DependencyObject()))
            {
                return true;
            }
            else
            {
                return false;
            }
#endif
        }
    }


Posted by CoolDragon

댓글을 달아 주세요

2017.02.24 12:39

어떤 현업께서 IIS가 자동으로 설치가 가능하냐고 물었다. (다 되는건 아니니까 난 안된다고 했다. ㅋㅋ)

OS의 지원 여부에 따라서 command line 또는 powershell로 설치가 가능 할 것 같다. 이 기능을 이용하여 OS가 부팅되면 IIS의 설치여부를 비교하여 설치 명령어를 실행시키면 되지 않을까 하는게 본 필자의 생각이다.


1) 필자는 C# 을 주로 다루는 개발자이므로 아래의 코드와 같이 레지스트리를 비교하여 IIS설치여부를 비교한다.

private static bool IsIisInstalled() => Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\InetStp", "VersionString", null) != null;

※ HKLM\Software\Microsoft\InetStp\MajorVersion 레지스트리를 통해 설치버전도 비교 가능



2) command에서 사용할 수 있는 설치명령어로 IIS를 설치한다.

pkgmgr은 deprecated 되었다고 해서 DISM을 사용하라고 하는데 내 OS(Windows 10)에서는 설치가 가능했다.

다른 OS버전에서는 사용이 가능한지는 해당 OS에서 적용해봐야지 알 수 있을 것 같다.


일반권한으로 실행해도 가능

c:\> start /w pkgmgr /iu:IIS-WebServerRole;IIS-WebServer;IIS-CommonHttpFeatures;IIS-StaticContent;IIS-DefaultDocument;IIS-DirectoryBrowsing;IIS-HttpErrors;IIS-ApplicationDevelopment;IIS-ISAPIExtensions;IIS-ISAPIFilter;IIS-NetFxExtensibility45;IIS-ASPNET45;NetFx4Extended-ASPNET45;IIS-NetFxExtensibility;IIS-ASPNET;IIS-HealthAndDiagnostics;IIS-HttpLogging;IIS-RequestMonitor;IIS-Security;IIS-RequestFiltering;IIS-HttpCompressionStatic;IIS-WebServerManagementTools;IIS-ManagementConsole;WAS-WindowsActivationService;WAS-ProcessModel;WAS-NetFxEnvironment;WAS-ConfigurationAPI


관리자권한으로 실행

c:\> START /WAIT DISM /Online /Enable-Feature /FeatureName:IIS-ApplicationDevelopment /FeatureName:IIS-ASP /FeatureName:IIS-ASPNET /FeatureName:IIS-ASPNET45 /FeatureName:IIS-BasicAuthentication /FeatureName:IIS-CGI /FeatureName:IIS-ClientCertificateMappingAuthentication /FeatureName:IIS-CommonHttpFeatures /FeatureName:IIS-CustomLogging /FeatureName:IIS-DefaultDocument /FeatureName:IIS-DigestAuthentication /FeatureName:IIS-DirectoryBrowsing /FeatureName:IIS-FTPExtensibility /FeatureName:IIS-FTPServer /FeatureName:IIS-FTPSvc /FeatureName:IIS-HealthAndDiagnostics /FeatureName:IIS-HostableWebCore /FeatureName:IIS-HttpCompressionDynamic /FeatureName:IIS-HttpCompressionStatic /FeatureName:IIS-HttpErrors /FeatureName:IIS-HttpLogging /FeatureName:IIS-HttpRedirect /FeatureName:IIS-HttpTracing /FeatureName:IIS-IIS6ManagementCompatibility /FeatureName:IIS-IISCertificateMappingAuthentication /FeatureName:IIS-IPSecurity /FeatureName:IIS-ISAPIExtensions /FeatureName:IIS-ISAPIFilter /FeatureName:IIS-LegacyScripts /FeatureName:IIS-LegacySnapIn /FeatureName:IIS-LoggingLibraries /FeatureName:IIS-ManagementConsole /FeatureName:IIS-ManagementScriptingTools /FeatureName:IIS-ManagementService /FeatureName:IIS-Metabase /FeatureName:IIS-NetFxExtensibility /FeatureName:IIS-NetFxExtensibility45 /FeatureName:IIS-ODBCLogging /FeatureName:IIS-Performance /FeatureName:IIS-RequestFiltering /FeatureName:IIS-RequestMonitor /FeatureName:IIS-Security /FeatureName:IIS-ServerSideIncludes /FeatureName:IIS-StaticContent /FeatureName:IIS-URLAuthorization /FeatureName:IIS-WebDAV /FeatureName:IIS-WebServer /FeatureName:IIS-WebServerManagementTools /FeatureName:IIS-WebServerRole /FeatureName:IIS-WindowsAuthentication /FeatureName:IIS-WMICompatibility /FeatureName:WAS-ConfigurationAPI /FeatureName:WAS-NetFxEnvironment /FeatureName:WAS-ProcessModel /FeatureName:WAS-WindowsActivationService


※ 이외에 다른방법은 분명히 있을 것이 분명하므로 이것만이 정답은 아님을 말씀드립니다.


참고:

http://stackoverflow.com/questions/37846864/how-to-know-iis-installed-or-not-programmatically

http://stackoverflow.com/questions/32097336/programmatically-enable-install-iis

Posted by CoolDragon

댓글을 달아 주세요

2017.01.11 10:47

로또 번호 수집기

LottNumberoCollector.zip



1. HttpClient를 이용하여 html 다운로딩 후

2. HttpAgilityPack 패키지를 이용한 HTML 파싱


Posted by CoolDragon

댓글을 달아 주세요

2016.05.26 14:17

c#에서의 정규식

string tmp = System.Text.RegularExpressions.Regex.Replace("abce!@#%123123가나다라", "[^0-9a-zA-Zㄱ-힗]+", "");

Posted by CoolDragon

댓글을 달아 주세요

2015.09.18 19:54

잡설

나는 Entity Framework는 그저 Link to SQL의 확장 정도로 인식해 왔다. 하지만 많은 유튜브 동영상 강좌를 보니 생각보다 다양한 하고 복잡한 프로그래밍 방식을 제공하는 것 같았다. 본인 프로그래밍 방식은 RDBMS에 프로시저 등을 생성하고 코드단에서 그 프로시저들을 호출하는 형태로 작업을 많이 해왔다. 그래서 최소한의 필요 데이터 만을 가져오는 것을 지향해서 테이블 단위의 Model을 생성하기 보다는 그때 그때 필요에 의해 모델들을 생성하다 보니 중복되는 code들이 늘어나는 것을 느꼈다. 특히 Relation에 엮여있는 테이블들의 데이터는 어떤 액션을 하느냐에 따라서 더 그런거 같더라.. 포스팅을 하는 지금 다시 생각해 보면 내가 한 코드단 모델링 방식은 잘 못 설계한 것이라는 생각이 든다. 잡설은 여기까지 하고 Entity Framework에 대한 사용법을 정리해보고자 한다.


Pre-Requisite

Entity Framework Power Tools 설치 (선택된 데이터베이스의 스키마를 자동으로 c#코드로 제너레이션 해준다.)

 - https://visualstudiogallery.msdn.microsoft.com/72a60b14-1581-4b9b-89f2-846072eff19d (VS2015 지원안함)

 - https://visualstudiogallery.msdn.microsoft.com/ee4fcff9-0c4c-4179-afd9-7a2fb90f5838


Development Method

 - Database first: 데이터베이스에 접속하여 스키마를 통하여 모델과 엔티티를 자동생성

 - Model First: 비쥬얼 스튜디오에서 모델을 직접 설계하고 관계도를 만들면 엔티티가 자동생성 (ERD와 비슷)

 - Code First: 자동 생성 없이 엔티티와 DBContext를 상속받은 클래스를 개발자가 직접 작성


Package Manager Console

# entity framework 설치 (Nuget을 사용할 수 있다.)

PM> install-package entityframework


# 데이터베이스의 스키마 정보가 c# 코드로 생성(자동 제너레이션)

PM> enable-migrations


# 데이터베이스의 스키마와 c#코드상에 스키마 정보를 비교하여 변경된 스키마 정보를 yyyyMMddHHmmss_FileName이라는 c#파일로 생성

PM> add-migration FileName


# 아래 명령어를 통하여 변경된 스키마를 데이터베이스에 적용

PM> Update-Database


# 데이터베이스에 적용된 스키마 롤백 (선택된 파일의 상태때로 되돌아 간다. 즉, 선택 파일 이후에 변경되었던 스키마 정보는 모두 롤백된다.)

PM> Update-Database -targetmigration 마이그레이션파일명(.cs제외)


# 최초의 스키마 정보에서부터 타켓으로 변경된 스키마 정보(yyyyMMddHHmmss_FileName)가 스크립트로 생성

PM> Update-Database -Script -SourceMigration: @InitialDatabase - TargetMigration: yyyyMMddHHmmss_FileName


DbContext

public class Employee

{

  public string Id {get; set;}

  public string Name {get; set;}

}


public class EmployeeDBContext : DbContext

{

  public DbSet<Employee> Employees {get; set;}


  protected override void OnModelCreating(DbModelBuilder modelBuilder)

  {

    // 여기에 Entity의 컬럼 속성 및 테이블/프로시져 맵핑 등을 설정할 수 있다.

    // 테이블명이 복수형으로 만들어지는 것을 방지

    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

    // Employee에 DB에 프로시져 자동 생성 및 맵핑

    modelBuilder.Entity<Employee>().MapToStoredProcedures

    (p => p.Insert(i => i.HasName("insertEmployee"))

               .Update(i => i.HasName("UpdateEmployee"))

               .Delete(i => i.HasName("DeleteEmployee")));

    base.OnModelCreating(modelBuilder)

  }

}


Pattern

 - Repositories Pattern

 - Unit of Work


DB Initializer

// DB 초기화 클래스 생성

public class DBInitializer : DropCreateDatabaseIfModelChanges<EmployeeDBContext>

{

  protected override void Seed(EmployeeDBContext context)

  {

    // 여기에 Context에 DataSet<Entity>로 선언된 프로퍼티의 기준 데이터를 생성해 줄 수 있다.

    base.Seed(context); 

  }

}

// Main() 함수나 Global.asax 의 실행부에 아래 함수를 호출하거나

System.Data.Entity.Database.SetInitializer(new DBInitializer());

// 또는 app.config나 web.config의 <entityframwork>에서 설정이 가능하다.

  <entityFramework>

    <contexts>

      <context type="Context Class Name, DLL Name">

        <databaseInitializer type="DBInitializer, DLL Name" />

      </context>

    </contexts>



Attribute

[SoftDelete("Property Name")]

모델 클래스에 SoftDelete()라는 속성을 선언하면 DB에 쿼리를 만드는 시점 Command Tree Interceptor 에서 그 쿼리를 가로채 실제 요청쿼리에 맞게 변환작업을 할 수 있게 한다.

이 기능이 구현하기 위해서는 Custom Attribute class 와 IDbCommandTreeInterceptor 인터페이스를 상속받은 class를 만들어 주어야 한다.


[DisplayFormat(DataFormatString = "{0:C0}")]



Tutorial

http://www.entityframeworktutorial.net/code-first/entity-framework-code-first.aspx


참조

https://www.youtube.com/playlist?list=PL6n9fhu94yhUPBSX-E2aJCnCR3-_6zBZx

https://www.youtube.com/watch?v=iwEG1M2ONrw

https://www.youtube.com/watch?v=vspEYmp6zWc

https://www.youtube.com/watch?v=i9Il79a2uBU

Posted by CoolDragon

댓글을 달아 주세요