Dapper Repository

MicroORM


관련 자료

https://dapper.phnx47.net/

 

MicroOrm.Dapper.Repositories

CRUD for Dapper

dapper.phnx47.net

https://github.com/phnx47/MicroOrm.Dapper.Repositories

 

phnx47/MicroOrm.Dapper.Repositories

CRUD for Dapper. Contribute to phnx47/MicroOrm.Dapper.Repositories development by creating an account on GitHub.

github.com

 

 

 

 

 



 

 

[그림1] MicrORM을 통한 쿼리 조회

 

 

[그림2] Repository 클래스 선언

 

아래는 관련 소스 파일을 첨부합니다.

MicroOrm.Dapper.Repositories-master.zip
0.08MB

C#에서 Firebase 사용하기


관련 자료

 

https://github.com/step-up-labs

 

Step Up Labs

Public repos of Step Up Labs, Inc. We love open-source! - Step Up Labs

github.com

https://github.com/aguacongas/Identity.Firebase

 

aguacongas/Identity.Firebase

ASP.NET Identity Firebase Provider. Contribute to aguacongas/Identity.Firebase development by creating an account on GitHub.

github.com

https://github.com/step-up-labs/firebase-authentication-dotnet

 

step-up-labs/firebase-authentication-dotnet

C# library for Firebase Authentication. Contribute to step-up-labs/firebase-authentication-dotnet development by creating an account on GitHub.

github.com

https://github.com/ziyasal/FireSharp

 

ziyasal/FireSharp

An asynchronous .Net client library for Firebase. Contribute to ziyasal/FireSharp development by creating an account on GitHub.

github.com



 

[그림] Firebase logo

 

 파이어베이스가 무엇인지는 다른 사이트(https://mailmail.tistory.com/42)에서 많은 자료들이 나와 있다

  1. 실시간 데이터 베이스
  2. 인증
  3. 클라우드 저장소
  4. 클라우드 함수
  5. Crash
  6. ...

이번 포스팅에서는 정식으로 제공되지 않는 C# 라이브러리를 통해서 .Net에서 사용할 수 있는 방안을 찾는 내용이 되겠다.

 

 

[그림] Firebase intro 화면

 

파이어베이스의 가격 정책 링크 https://firebase.google.com/pricing

 

Firebase

무료로 Firebase를 시작하고 전 세계 수백만 명의 사용자로 확장하며 사용한 만큼만 비용을 지불합니다.

firebase.google.com

 


 오래전에 만들어진 C# 라이브러리는 FirebaseSharp(https://github.com/bubbafat/FirebaseSharp), FireSharp (https://github.com/ziyasal/FireSharp)이 있는데, FireSharp가 최근까지 활동한 이력을 확인할 수 있었다. 그래서 FireSharp를 사용하려고 하였는데, 마지막에 "Step Up Labs"에서 작성한 "firebase-database-dotnet"을 알게 되었다.

이 라이브러리를 사용하면 실시간 데이터베이스에서 보내주는 Pub/Sub 데이터를 안정적으로 받아서 처리할 수 있다고 제작자가 자랑을 하였다. 하지만 이 라이브러리는 모든 Firebase의 기능을 담고 있지는 않기 때문에 위에 소개한 FireSharp(https://github.com/ziyasal/FireSharp) 라이브러리를 병행해서 사용해야 하겠다. 그리고 별도로 "aguacongas"라는 분도 Firebase용 라이브러리를 만들어서 공유해 두었기에 이것도 참조 하면 되겠다.

 

참고로 FireSharp는 Dotnet Core 버전을 지원하지 않는다.

 

 

 

 

 

CreateProcessAsUser 으로 다른 권한으로 실행하기


관련 자료

https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasusera

 

CreateProcessAsUserA function (processthreadsapi.h)

Creates a new process and its primary thread. The new process runs in the security context of the user represented by the specified token.

docs.microsoft.com

https://support.microsoft.com/ko-kr/help/165194/createprocessasuser-windowstations-and-desktops

 

https://support.microsoft.com/ko-kr/help/165194/createprocessasuser-windowstations-and-desktops

쿠키가 사용되고 있지 않습니다. 쿠키를 사용하고 페이지를 새로 고치세요.

support.microsoft.com

https://mynotepad.tistory.com/176

 

VIsta 이상 버전에서 Windows Service 에 등록된 프로그램에서 다른 프로그램 띄우기

Windows Vista 이상 버전에서는 세션 관리정책으로 인해서 Windows 의 Service 에 등록된 프로그램이 직접 다른 프로그램을 띄우지 못하게 막았다. 보안상의 이유로 이렇게 한 듯 한데. 이로 인해서 서비스로 등록..

mynotepad.tistory.com

 



 

 

 아래 코드를 통해서 다른 계정의 UI와 권한으로 실행할 수 있다.

 

public class ProcessLauncher
    {
        #region Structures
        [StructLayout(LayoutKind.Sequential)]
        public struct STARTUPINFO
        {
            public Int32 cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public Int32 dwX;
            public Int32 dwY;
            public Int32 dwXSize;
            public Int32 dwXCountChars;
            public Int32 dwYCountChars;
            public Int32 dwFillAttribute;
            public Int32 dwFlags;
            public Int16 wShowWindow;
            public Int16 cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public Int32 dwProcessID;
            public Int32 dwThreadID;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public Int32 Length;
            public IntPtr lpSecurityDescriptor;
            public bool bInheritHandle;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct ProfileInfo
        {
            public int dwSize;
            public int dwFlags;
            public string lpUserName;
            public string lpProfilePath;
            public string lpDefaultPath;
            public string lpServerName;
            public string lpPolicyPath;
            public IntPtr hProfile;
        }
        #endregion

        #region Enumerations
        public enum SECURITY_IMPERSONATION_LEVEL
        {
            SecurityAnonymous,
            SecurityIdentification,
            SecurityImpersonation,
            SecurityDelegation
        }

        public enum TOKEN_TYPE
        {
            TokenPrimary = 1,
            TokenImpersonation
        }
        #endregion

        #region Constants
        //Use these for DesiredAccess
        private static uint STANDARD_RIGHTS_REQUIRED = 0x000F0000;
        private static uint STANDARD_RIGHTS_READ = 0x00020000;
        private static uint TOKEN_ASSIGN_PRIMARY = 0x0001;
        private static uint TOKEN_DUPLICATE = 0x0002;
        private static uint TOKEN_IMPERSONATE = 0x0004;
        private static uint TOKEN_QUERY = 0x0008;
        private static uint TOKEN_QUERY_SOURCE = 0x0010;
        private static uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
        private static uint TOKEN_ADJUST_GROUPS = 0x0040;
        private static uint TOKEN_ADJUST_DEFAULT = 0x0080;
        private static uint TOKEN_ADJUST_SESSIONID = 0x0100;
        private static uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
        private static uint TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID);

        private const int MAXIMUM_ALLOWED = 0x2000000;

        //Process Creation Flags
        private const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400;
        private const uint CREATE_NO_WINDOW = 0x08000000;
        private const uint CREATE_NEW_CONSOLE = 0x00000010;
        private const uint DETACHED_PROCESS = 0x00000008;

        private const UInt32 INFINITE = 0xFFFFFFFF;
        private const UInt32 WAIT_ABANDONED = 0x00000080;
        private const UInt32 WAIT_OBJECT_0 = 0x00000000;
        private const UInt32 WAIT_TIMEOUT = 0x00000102;
        #endregion

        #region Win32 API Imports



        [
           DllImport("kernel32.dll",
              EntryPoint = "CloseHandle", SetLastError = true,
              CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)
        ]
        public static extern bool CloseHandle(IntPtr handle);

        [
           DllImport("advapi32.dll",
              EntryPoint = "CreateProcessAsUser", SetLastError = true,
              CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)
        ]
        public static extern bool
           CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine,
                               ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes,
                               bool bInheritHandle, uint dwCreationFlags, IntPtr lpEnvrionment,
                               string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo,
                               ref PROCESS_INFORMATION lpProcessInformation);

        [
           DllImport("advapi32.dll",
              EntryPoint = "DuplicateTokenEx")
        ]
        public static extern bool
           DuplicateTokenEx(IntPtr hExistingToken, uint dwDesiredAccess,
                            ref SECURITY_ATTRIBUTES lpThreadAttributes,
                            Int32 ImpersonationLevel, Int32 dwTokenType,
                            ref IntPtr phNewToken);

        [DllImport("advapi32.dll", SetLastError = true)]
        internal static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, ref IntPtr TokenHandle);

        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

        [DllImport("kernel32.dll")]
        private static extern uint WTSGetActiveConsoleSessionId();

        [DllImport("wtsapi32.dll", SetLastError = true)]
        static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);

        [DllImport("kernel32.dll")]
        static extern bool GetExitCodeProcess(IntPtr hProcess, ref int lpExitCode);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

        [DllImport("userenv.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);

        [DllImport("userenv.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);

        [DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool LoadUserProfile(IntPtr hToken, ref ProfileInfo lpProfileInfo);

        [DllImport("Userenv.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool UnloadUserProfile(IntPtr hToken, IntPtr lpProfileInfo);

        #endregion

        public static void Start(ProcessStartInfo processStartInfo)
        {
            var primaryToken = IntPtr.Zero;
            var userToken = IntPtr.Zero;
            var hProcess = IntPtr.Zero;

            var pi = new PROCESS_INFORMATION();
            var sa = new SECURITY_ATTRIBUTES();
            sa.Length = Marshal.SizeOf(sa);

            var profileInfo = new ProfileInfo();
            profileInfo.dwSize = Marshal.SizeOf(profileInfo);
            profileInfo.lpUserName = Environment.UserName;
            profileInfo.dwFlags = 1;


            try
            {
                primaryToken = GetCurrentWinLogonToken();
                userToken = GetCurrentUserToken();
                var si = new STARTUPINFO();
                si.cb = Marshal.SizeOf(si);
                si.lpDesktop = "WinSta0\\Default";
 
                IntPtr lpEnvironment = IntPtr.Zero;
                if (!CreateEnvironmentBlock(out lpEnvironment, GetCurrentUserToken(), false))
                    throw new Win32Exception(Marshal.GetLastWin32Error());

                //if (!LoadUserProfile(userToken, ref profileInfo))
                //    throw new Win32Exception(Marshal.GetLastWin32Error());

                if (!CreateProcessAsUser(
                                            primaryToken,
                                            null,
                                            string.Format("\"{0}\" {1}", processStartInfo.FileName.Replace("\"", "\"\""), processStartInfo.Arguments),
                                            ref sa, ref sa,
                                            false, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, lpEnvironment,
                                            null, ref si, ref pi
                                    ))
                    throw new Win32Exception(Marshal.GetLastWin32Error());

                DestroyEnvironmentBlock(lpEnvironment);

            }
            finally
            {
                if (pi.hProcess != IntPtr.Zero)
                    CloseHandle(pi.hProcess);
                if (pi.hThread != IntPtr.Zero)
                    CloseHandle(pi.hThread);
                if (primaryToken != IntPtr.Zero)
                    CloseHandle(primaryToken);
                //UnloadUserProfile(userToken, profileInfo.hProfile);
            }


        }

        private static IntPtr GetCurrentWinLogonToken()
        {
            int winlogonPid = 0;
            var hToken = IntPtr.Zero;
            var hDupedToken = IntPtr.Zero;
            var hProcess = IntPtr.Zero;

            var sa = new SECURITY_ATTRIBUTES();
            sa.Length = Marshal.SizeOf(sa);
            IntPtr pServer = IntPtr.Zero;

            uint dwSessionId = GetCurrentUserSessionId();

            // obtain the process id of the winlogon process that is running within the currently active session
            Process[] processes = Process.GetProcessesByName("winlogon");
            foreach (Process p in processes)
            {
                if (p.SessionId == dwSessionId)
                {
                    winlogonPid = p.Id;
                }
            }

            // obtain a handle to the winlogon process
            hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
            if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hToken))
                throw new Win32Exception(Marshal.GetLastWin32Error());

            if (!DuplicateTokenEx(
                    hToken,
                    TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS,
                    ref sa,
                    (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
                    (int)TOKEN_TYPE.TokenPrimary,
                    ref hDupedToken
                ))
                throw new Win32Exception(Marshal.GetLastWin32Error());

            return hDupedToken;
        }

        private static uint GetCurrentUserSessionId()
        {
            uint dwSessionId = 0;
            using (ITerminalServer localServer = (new TerminalServicesManager()).GetLocalServer())
            {
                foreach (ITerminalServicesSession current in localServer.GetSessions())
                {
                    if (current.ConnectionState == ConnectionState.Active)
                    {
                        dwSessionId = (uint)current.SessionId;
                        break;
                    }
                }
            }

            return dwSessionId;
        }

        private static IntPtr GetCurrentUserToken()
        {
            var hToken = IntPtr.Zero;
            var hDupedToken = IntPtr.Zero;

            var sa = new SECURITY_ATTRIBUTES();
            sa.Length = Marshal.SizeOf(sa);
            IntPtr pServer = IntPtr.Zero;

            uint dwSessionId = GetCurrentUserSessionId();

            if (!WTSQueryUserToken(dwSessionId, out hToken))
                throw new Win32Exception(Marshal.GetLastWin32Error());

            if (!DuplicateTokenEx(
                    hToken,
                    TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS,
                    ref sa,
                    (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
                    (int)TOKEN_TYPE.TokenPrimary,
                    ref hDupedToken
                ))
                throw new Win32Exception(Marshal.GetLastWin32Error());

            return hDupedToken;
        }


    }

[코드] 특정 계정의 토큰 값으로 사용자 계정으로 프로세스 실행하는 코드

커스텀 브라우저 프로토콜로 응용프로그램 실행

(Custom Url Schemes in windows)

 


관련 자료

https://support.shotgunsoftware.com/hc/ko/articles/219031308

 

커스텀 브라우저 프로토콜을 사용하여 응용프로그램 실행

목차 프로토콜 등록 Windows에서 프로토콜 등록 OSX에서 프로토콜 등록 Linux에서 프로토콜 등록 실제로 가장 잘 접할 수 있는 AMI(액션 메뉴 항목) 버전은 로컬 컴퓨터에서 응용프로그램 또는 스크립트를 실행하는 AMI입니다. 이 AMI가 작동하도록 하려면 실행하려는 스크립트나 응용프로그램과 브라우저 간 연결을 설정해 주어야 합니다...

support.shotgunsoftware.com

https://docs.microsoft.com/ko-kr/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa767914(v=vs.85)

 

Registering an Application to a URI Scheme (Windows)

Registering an Application to a URI Scheme 07/13/2016 5 minutes to read In this article --> The About Asynchronous Pluggable Protocols article describes how to develop handlers for Uniform Resource Identifier (URI) schemes. In some cases, it may be desirab

docs.microsoft.com

 



 

 

Official URI schemes

IANA(ICNN)에서 이미 여러 URI Scheme를 정의하고 관리하고 있다. http, mailto, magnet 외 다수가 있으며 상세 정보는 http://en.wikipedia.org/wiki/URI_scheme에서 확인할 수 있다.

Custom URI schemes

공식적으로 지정되고 관리되는 URI Scheme도 있지만 사용자가 직접 URI Scheme를 만들수도 있다. 대부분의 OS에서 URI Scheme을 직접 등록하고 설정할 수 있도록 지원하고 있으며 Andrond, iOS, Windows 등 시스템에 따라 각각 이를 등록하는 방법은 다르다.

 

 

 

Custom URI Scheme in Windows OS

 Windows에서는 Registry를 편집함으로써 URI Scheme를 등록할 수 있다. 보다 자세한 Custom URI Scheme의 등록방법은 MS site에서 확인할 수 있으며 아래와 같은 절차로 등록 할 수 있다.

  1. 레지스트리 편집기에서 다음 위치에 [HKEY_CLASSES_ROOT]를 열어보면 시스템에 등록된 확장자 정보 또는 URI Scheme 정보들을 볼 수 있다.
  2. [HKEY_CLASSES_ROOT]의 하위에 "Key"를 추가하여 URI Scheme을 등록할 수 있다. 여기서 "Key"의 이름이 바로 스키마 명이 되게 된다.
  3. 여기서는 "test"라는 URI Scheme명칭을 등록해보도록 하겠다.
  4. 추가된 "Key"에 "String Value"를 추가하자.
  5. 이름은 [URL Protocol]으로 지정하고 값은 공백("")으로 한다. 이 [URL Protocol]을 통해서 시스템은 이 [Key]가 URI Scheme이라는 것을 식별하게 된다.
  6. 이제 URI Scheme를 통해 실행될 기능을 설정하기 위해 새로운 "Key"를 등록하자.
  7. "Key"의 이름은 [shell]로 지정하면 된다.
  8. 이제 실행될 동작에 해당하는 이름을 가진 "Key"를 추가하면 된다. 여기서는 프로그램을 실행하는 "open"이라는 "Key"를 [shell] 하위에 추가하도록 하겠다.
  9. [open]하위에 다시 [command] Key를 추가하고 [command] Key의 '(Default)' 항목을 더블클릭하자.
  10. [문자열 편집]창이 나타나면 값으로 실행할 Application을 지정하자. 여기선 경로 주위에 쌍따옴표를 붙여야 한다.
  11. 만약 프로그램 실행 시 매개변수를 넘기고 싶다면 Application Path 뒤에 한칸 뛰우고 "%1"을 추가하면(쌍따옴표 포함) URI값이 Application으로 전달되게 된다.
  12. 아래 그림과 같이 위에서 작성한 URI Scheme를 포함한 링크를 작성하여 테스트 해보자.
  13. 아래와 같이 위에서 지정한 Application이 잘 열리는 것을 확인할 수 있다.

 

Refit: The automatic type-safe REST library for .NET Core, Xamarin and .NET


관련 자료

https://reactiveui.github.io/refit/

 

Refit: The automatic type-safe REST library for .NET Core, Xamarin and .NET

The automatic type-safe REST library for Xamarin and .NET

reactiveui.github.io

http://square.github.io/retrofit/

 

Retrofit

A type-safe HTTP client for Android and Java

square.github.io

 

 

 

 



 

 

 Refit은 Square의 Retrofit 라이브러리에서 크게 영향을받은 라이브러리이며 REST API를 라이브 인터페이스로 변환합니다. 간단하게 요약하면 인터페이스 정의 만으로도 REST API를 호출하여 데이터를 가져올 수 있게 해준다라는 것이다.

 

 예를 아래 코드를 통해 살펴 보자. 일단 인터페이스를 정의를 한다.

 

public interface IGitHubApi
{
    [Get("/users/{user}")]
    Task<User> GetUser(string user);
}

RestService 클래스는 HttpClient를 사용하여 호출을 수행하는 IGitHubApi 구현을 생성합니다.

var gitHubApi = RestService.For<IGitHubApi>("https://api.github.com");
var octocat = await gitHubApi.GetUser("octocat");

위와 같은 짧은 코드만으로 외부 자원을 사용하도록 할 수 있다.

 

 

 

ReactiveUI and the MVVM Pattern in WPF


관련 자료

 

https://reactiveui.net/

 

An advanced, composable, reactive model-view-viewmodel framework

Declarative Describe what you want, not how to do it & rejoice in the increased readability of your code. Code is communication between people, that also happens to run on a computer. If you optimise for reading by humans, then over a long time your projec

reactiveui.net

https://github.com/reactiveui

 

ReactiveUI

Use the Reactive Extensions for .NET to create elegant, testable user interfaces that run on any mobile or desktop platform. - ReactiveUI

github.com

https://www.toptal.com/wpf/reactiveui-and-mvvm-in-wpf

 

ReactiveUI and the MVVM Pattern in WPF Applications

I will implement a WPF app using ReactiveUI with the MVVM pattern, and uses it to access a REST API. This app will be able to track cars and their locations, take information pulled from a simulated source, and display this information to the user in a Bin

www.toptal.com

 

 



 

[그림1] ReactiveUI

 

 Reactive Extensions for .NET을 사용하여 모바일 또는 데스크톱 플랫폼에서 실행되는 우아하고 테스트 가능한 사용자 인터페이스를 만들 수 있다. 

 

[그림2] ReactiveUI code example

 "그림2"에서와 같은 코드로 이벤트를 잡아내고, 처리 로직을 세울 수 있다.

 

 

[그림3] example

 

 

[그림4] MVVM flow

 

 "그림4"는 MVVM의 흐름을 나타낸것이다. MV-VM으로서 처리 로직과, UI의 분리를 통해 디자이너와의 협업성을 향상 시킬 수 있다. MV* 아키텍처의 아류로서 MS에서 발표 하였지만, 대부분은 WPF에서 사용중이다. 하지만 javascript 진영이나, 기타 프레임워크에서 MV*와 바인딩 엔진 개념을 도입해서 사용하는 프로젝트가 늘어나고 있는 추세이긴 하다.

 

 

아래는 각 언어와 플랫폼별로 라이브러리를 추가하는 정보를 나열하였다. 참고하여 프로젝트에 추가하면 되겠다.

Platform ReactiveUI Package Package
.NET Standard ReactiveUI None
  ReactiveUI.Fody None
Unit Testing ReactiveUI.Testing None
Universal Windows ReactiveUI ReactiveUI.Events
WPF ReactiveUI.WPF ReactiveUI.Events.WPF
Windows Forms ReactiveUI.WinForms ReactiveUI.Events.WinForms
Xamarin.Forms ReactiveUI.XamForms ReactiveUI.Events.XamForms
Xamarin.Essentials ReactiveUI ReactiveUI.Events.XamEssentials
Xamarin.Android ReactiveUI.AndroidSupport ReactiveUI.Events
Xamarin.iOS ReactiveUI ReactiveUI.Events
Xamarin.Mac ReactiveUI ReactiveUI.Events
Tizen ReactiveUI ReactiveUI.Events
Avalonia Avalonia.ReactiveUI None

[표1] 참조 라이브러리

C# 난독화 - obfuscar


참조 URL
  1. https://www.obfuscar.com/
  2. https://github.com/lextm/obfuscar
  3. https://github.com/lextm/obfuscar_example
  4. http://docs.obfuscar.com/en/latest/
  5. https://yck1509.github.io/ConfuserEx/
  6. https://github.com/yck1509/ConfuserEx

 











EntityFramework Core performance


참조 URL
  1. https://youtu.be/x3cymeg9Lpo?t=1255

 


 Entity Framework Core는 기존 하위 버전보다 약 80% 정도의 속도 향상이 된듯하다.






시간이 없어서 검증은 차후에 해봐야 겠다.















Windows Service에서 디비깅을 쉽게 하는 방법


참조 URL
  1. http://devsw.tistory.com/153
  2. https://msdn.microsoft.com/ko-kr/library/cktt23yw.aspx
  3. http://www.codeproject.com/Articles/10153/Debugging-Windows-Services-under-Visual-Studio-NET
  4. http://blog.aliencube.org/ko/2014/04/30/developing-windows-service-with-topshelf/
  5. http://blogs.microsoft.co.il/alon_nativ/2011/02/01/creating-windows-service-using-topshelf/

 


1. 콘솔 프로그램을 사용하여 디버깅

[코드 1] 콘솔에서 디비깅 #1



[코드 2] 콘솔에서 디비깅 #2



위와 같이 별도의 프로젝트 또는 같은 프로젝트에서 위와 같이 구성하여 콘솔 실행으로 개발하고 디버깅을 시작할 수 있다.



2. "Diagnostics.Debugger" 사용하여 디버깅

[코드 3] 윈도우 서비스에서 디버깅



3. "Topshelf"를 사용하여 디버깅


[코드 4] Topshelf










Visual Studio "14" CTP Now Available


참조 URL
  1. http://blogs.msdn.com/b/csharpfaq/archive/2014/06/03/visual-studio-14-ctp-now-available.aspx
  2. http://www.visualstudio.com/en-us/downloads/visual-studio-14-ctp-vs
  3. http://go.microsoft.com/fwlink/?LinkId=399010
  4. http://msdn.microsoft.com/en-us/library/zzszcehe.aspx

 



 Visual studio 2013의 차기 버전이 '14' CTP가 나왔다.  추가된 대표 기능으로 는 아래와 같다.

  • C# and VB with the .NET Compiler Platform ("Roslyn")
    (open-source compiler as a service)

  • ASP.NET vNext

  • C++ 11/14

이 밖에도 자잘하게 C#을 위한 리팩토링 기능이 향상 되었으며, 웹 탬플릿(vNext) 추가등 여러가지 자잘한 기능 향상이 되었다.



 

 

 

 

 그리고 마지막으로 쉽게 피드백을 보낼 수 있는 방법으로 Send a smile로 쉽게 보낼 수 있는 기능이 있다.

 

 

 








 

+ Recent posts