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 버전을 지원하지 않는다.

 

 

 

 

 

웹에서 지도 연동 라이브러리 - LeafLetJS


관련 자료

https://leafletjs.com/

 

Leaflet — an open-source JavaScript library for interactive maps

Leaflet is a modern, lightweight open-source JavaScript library for mobile-friendly interactive maps.

leafletjs.com

https://github.com/Leaflet/Leaflet

 

Leaflet/Leaflet

:leaves: JavaScript library for mobile-friendly interactive maps - Leaflet/Leaflet

github.com

 

 



 

 

[그림] LeafLetJS logo

 

 

 

[그림] leaftlet을 사용해 연동한 지도 화면

 

 

 

Free bootstrap template - 추천 무료 부트스트랩 템플릿


관련 자료

https://github.com/ColorlibHQ/AdminLTE

 

ColorlibHQ/AdminLTE

AdminLTE - Free Premium Admin control Panel Theme Based On Bootstrap 3.x - ColorlibHQ/AdminLTE

github.com

https://adminlte.io/

 

Free Bootstrap Admin Template | AdminLTE.IO

Bootstrap is raking over the world and so is React. Therefore, we decided to showcase these outstanding React Bootstrap templates May 20, 2019

adminlte.io

https://github.com/weituotian/AdminLTE-With-Iframe

 

weituotian/AdminLTE-With-Iframe

AdminLTE With Iframe- 基于AdminLTE适合中国国情的网站模版. Contribute to weituotian/AdminLTE-With-Iframe development by creating an account on GitHub.

github.com

https://weituotian.github.io/AdminLTE-With-Iframe/pages/index_iframe.html

 

AdminLTE 2 | with iframe

 

weituotian.github.io

https://themequarry.com/

 

Premium Website Themes & Templates | ThemeQuarry

DETAILS DEMO

themequarry.com



 

 

The MIT License (MIT) 라이센스로 배포가 되고 있는 무료 부트스트랩 템플릿이다. ( 링크

 

[그림] AdminLTE 템플릿 대쉬보드 화면

 

다른 github에서 "weituotian"라는 분이 iframe용으로 탭 네비게이션 관리자 페이지를 만들었다. 탭 네비게이션이 필요한 사람은 이 템플릿을 사용해도 되겠다.

 

[그림] AdminLTE with iframe 대쉬보드 화면

 

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;
        }


    }

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

BootboxJS — Bootstrap의 모달을 쉽게 컨트롤 하자


관련 자료

http://bootboxjs.com/

 

Bootbox.js — alert, confirm and flexible dialogs for the Bootstrap framework

Bootbox provides three functions, alert, confirm, and prompt, whose aim is to mimic their native JavaScript equivalents. Here’s the simplest possible example: bootbox.alert("Hello world!"); Run example Compare that to the code you’d have to write without B

bootboxjs.com

https://github.com/makeusabrew/bootbox

 

makeusabrew/bootbox

Wrappers for JavaScript alert(), confirm() and other flexible dialogs using Twitter's bootstrap framework - makeusabrew/bootbox

github.com

 



 

 

 

[그림] bootbox logo

 

아래와 같은 코드로 쉽게 Bootstrap의 모달을 사용할 수 있다.

 

[그림] alert 모달 사용 예제 화면

 

 

아래는 웹 페이지에서 jquery와 통합한 소스 ( 홈페이지에 나와 있는 가이드 소스 )

<!-- set up the modal to start hidden and fade in and out -->
<div id="myModal" class="modal fade">
    <div class="modal-dialog">
        <div class="modal-content">
            <!-- dialog body -->
            <div class="modal-body">
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                Hello world!
            </div>
            <!-- dialog buttons -->
            <div class="modal-footer"><button type="button" class="btn btn-primary">OK</button></div>
        </div>
    </div>
</div>
        
<!-- sometime later, probably inside your on load event callback -->
<script>
    $("#myModal").on("show", function() {    // wire up the OK button to dismiss the modal when shown
        $("#myModal a.btn").on("click", function(e) {
            console.log("button pressed");   // just as an example...
            $("#myModal").modal('hide');     // dismiss the dialog
        });
    });
        
    $("#myModal").on("hide", function() {    // remove the event listeners when the dialog is dismissed
        $("#myModal a.btn").off("click");
    });
            
    $("#myModal").on("hidden", function() {  // remove the actual elements from the DOM when fully hidden
        $("#myModal").remove();
    });
            
    $("#myModal").modal({                    // wire up the actual modal functionality and show the dialog
        "backdrop"  : "static",
        "keyboard"  : true,
        "show"      : true                     // ensure the modal is shown immediately
    });
</script>

 

bootbox 5.0 부터는 bootstrap 4을 지원한다.

'Javascript' 카테고리의 다른 글

[Javascript] svelte  (0) 2019.12.03
[Javascript] ag-grid  (0) 2019.10.20
Mobx - Simple, scalable state management  (0) 2019.05.11
BootstrapVue  (0) 2019.05.02
브라우저에서 particle을 만들어 보자  (0) 2019.04.19

Google 웹 개발자를 위한 점검 사이트 Web.dev 사이트


관련 자료

https://web.dev/

 

web.dev  |  web.dev

Get the web's modern capabilities on your own sites and apps with useful guidance and analysis from web.dev.

web.dev

 



 

[그림1] web.dev 사이트

 

 구글에서 만든 web.dev 사이트는 웹사이트에 대한 감사를 실행하고 성능과 웹 접근성 테스트 SEO에 대한 점검 리포트를 작성해 준다. 이 도구로 얼마나 잘 만들어 졌는제를 측정할 수 있는 도구이다.

 

아래는 네이버 사이트를 측정해 본 리포트이다.

 

 

[그림1] 네이버 점검 리포트

 

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

(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이 잘 열리는 것을 확인할 수 있다.

 

Mobx - Simple, scalable state management


관련 자료

https://github.com/mobxjs/mobx

 

mobxjs/mobx

Simple, scalable state management. Contribute to mobxjs/mobx development by creating an account on GitHub.

github.com

http://woowabros.github.io/experience/2019/01/02/kimcj-react-mobx.html

 

React에서 Mobx 경험기 (Redux와 비교기) - 우아한형제들 기술 블로그

안녕하세요 딜리버리플랫폼팀 김찬정입니다.

woowabros.github.io

https://medium.com/@jsh901220/mobx-%EC%B2%98%EC%9D%8C-%EC%8B%9C%EC%9E%91%ED%95%B4%EB%B3%B4%EA%B8%B0-a768f4aaa73e

 

Mobx 처음 시작해보기

리액트로 프로젝트를 진행하게 되면, state와 props 만으로는 데이터의 관리가 매우 어렵다는 것을 느끼게 된다. 대표적인 어려움으로는 밑의 그림과 같은 상황을 둘 수 있다.

medium.com

https://mobx.js.org/getting-started.html

 

MobX: Ten minute introduction to MobX and React

MobX Ten minute introduction to MobX and React MobX is a simple, scalable and battle tested state management solution. This tutorial will teach you all the important concepts of MobX in ten minutes. MobX is a standalone library, but most people are using i

mobx.js.org

https://brunch.co.kr/@hee072794/93

 

MobX + React 10분 튜토리얼

상태 관리 솔루션 MobX 튜토리얼 | * 이 글은 MobX의 MobX and React 튜토리얼을 번역한 글입니다. ** 오역 및 오탈자가 있을 수 있습니다. 발견하시면 제보해주세요! 개요 MobX은 간단하고 확장 가능하며 테스트를 거친 상태 관리 솔루션입니다. 이 튜토리얼은 10분 안에 MobX의 중요한 컨셉들을 모두 소개합니다. MobX는 독립적인 라이브러리지만 대부분의 사람들은 Rea

brunch.co.kr

 



 

 

[그림1] Mobx의 상태관리 흐름

 

 Redux, Mobx, Flux 모두 상태관리를 할 수 있는 라이브러리이다. ( 물론 각각의 다른 역할도 부가적으로 가지고 있기 때문에 절대적인 추천을 할 수는 없을 것이다. ). 상태관리를 통해 복잡한 코딩을 간단하게 업데이트를 할 수 있게 구성할 수 있다.

 

 

 

[그림2] logo

 

 

[그림3] 상태관리 흐름도

'Javascript' 카테고리의 다른 글

[Javascript] ag-grid  (0) 2019.10.20
BootboxJS — Bootstrap의 모달을 쉽게 컨트롤 하자  (0) 2019.05.27
BootstrapVue  (0) 2019.05.02
브라우저에서 particle을 만들어 보자  (0) 2019.04.19
nextjs - service side react framework  (0) 2019.04.16

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] 참조 라이브러리

+ Recent posts