<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>기억상기용</title>
    <link>https://dlsenfl.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 10:18:22 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>딸기우유중독</managingEditor>
    <item>
      <title>[WPF][별*] Seamless, Messaging Sample</title>
      <link>https://dlsenfl.tistory.com/entry/WPF%EB%B3%84-Seamless-Messaging-Sample</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;# WPF&amp;nbsp;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ComHost의 TargetFramework가 net9.0-windows 이라면&lt;br /&gt;사용하는 프로젝트도 TargetFramework 가 동일해야 COM 호출 가능.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하는 프로젝트의 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;TargetFramework&lt;span&gt; 가 다른 경우에 대처법.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1. 사용하는 프로젝트에 맞춰서 ComHost를 COM으로 등록한다.&lt;br /&gt;2. 사용하는 프로젝트 에 맞춰서 ComHost에 TargetFramework를 추가해서 빌드 후&amp;nbsp;&lt;br /&gt;ex) &amp;lt;TargetFrameworks&amp;gt;net6.0-windows;net9.0-windows&amp;lt;/TargetFrameworks&amp;gt; &lt;br /&gt;누겟 패키지 파일로 직접 참조해서 사용한다. (COM 호출을 안한다.)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;lt;TargetFramework&amp;gt;net9.0-windows&amp;lt;/TargetFramework&amp;gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;331&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnJbyk/dJMcabwVfvC/AlfmA1MelLZNyASjcxflo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnJbyk/dJMcabwVfvC/AlfmA1MelLZNyASjcxflo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnJbyk/dJMcabwVfvC/AlfmA1MelLZNyASjcxflo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnJbyk%2FdJMcabwVfvC%2FAlfmA1MelLZNyASjcxflo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;575&quot; height=&quot;331&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;331&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zDII8/dJMcaa5SnwA/gE1TcNEmuQOumx8vGAmnOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zDII8/dJMcaa5SnwA/gE1TcNEmuQOumx8vGAmnOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zDII8/dJMcaa5SnwA/gE1TcNEmuQOumx8vGAmnOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzDII8%2FdJMcaa5SnwA%2FgE1TcNEmuQOumx8vGAmnOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1668&quot; height=&quot;551&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;551&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ConnectorClientCallbackActions.cs&lt;/p&gt;
&lt;pre id=&quot;code_1775175291726&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using LS.Extension.Connector.Contract.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace LS.Extension.Connector.WpfApp.Models;

public class MessageCallback : IMessageCallback
{
    private readonly Action&amp;lt;string&amp;gt; _onMessageReceived;

    public MessageCallback(Action&amp;lt;string&amp;gt; onMessageReceived)
    {
        _onMessageReceived = onMessageReceived;
    }

    public void OnMessageReceived(string message)
    {
        _onMessageReceived?.Invoke(message);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MainWindow.xaml.cs&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;this.SourceInitialized ( or Loaded 이벤트 때) 가 되어야 Handle 값 얻을 수 있음&lt;/blockquote&gt;
&lt;pre id=&quot;code_1775175330259&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using LS.Extension.Connector.Contract.Interfaces;
using LS.Extension.Connector.WpfApp.Models;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;

namespace LS.Extension.Connector.WpfApp;

/// &amp;lt;summary&amp;gt;
/// Interaction logic for MainWindow.xaml
/// &amp;lt;/summary&amp;gt;
public partial class MainWindow : Window
{
    public static IChildClient ChildClient { get; private set; } = new ChildClient(); 
    public static IParentClient ParentClient { get; private set; } = new ParentClient();

    public string ThemeName { get; set; } = string.Empty;

    public MainWindow()
    {
        InitializeComponent();
        ParentClient.SetArguments(App.Args);
        var connectorId = ParentClient.GetConnectorId();
        if (!string.IsNullOrEmpty(connectorId))
        {
            try
            {
                this.SourceInitialized += AttachClient;
            }
            catch (Exception)
            {
                throw;
            }
        }
        //else
        {
            this.SourceInitialized += RegisterClient;
        }
    }
    #region ParentClient

    private void AttachClient(object? sender, EventArgs e)
    {
        string themeName = App.Args[3]?.Replace(&quot;/themeName=&quot;, &quot;&quot;).Trim() ?? string.Empty;

        if (!string.IsNullOrEmpty(themeName))
        {
            MainGrid.Background = Brushes.AntiqueWhite;
            ThemeName = string.Empty;
        }
        else
        {
            MainGrid.Background = Brushes.AliceBlue;
            ThemeName = &quot;Default&quot;;
        }
        var controlHandle = new WindowInteropHelper(this).Handle;
        ParentClient.AttachClient(controlHandle);
        ParentConnectorId.Text = $&quot;Connector ID: {ParentClient.GetConnectorId()}&quot;;
    }

    private void SendMessageToParentButton(object sender, RoutedEventArgs e)
    {
        ParentClient.SendMessage(ParentKeyTextBox.Text, ParentMessageTextBox.Text);
    }
    private void GetMessageFromParentButton(object sender, RoutedEventArgs e)
    {
        ParentMessage.Text = ParentClient.GetMessage(ParentKeyTextBox.Text);
    }
    private void SubscribeParentMessageButton(object sender, RoutedEventArgs e)
    {
        var key = ParentKeyTextBox.Text;
        var callback = new MessageCallback((message) =&amp;gt;
        {
            Dispatcher.Invoke(() =&amp;gt;
            {
                ParentMessage.Text = $&quot;[{key}] Received: {message}&quot;;
            });
        });
        ParentClient.SubscribeMessage(key, callback);
    }
    private void NewAttachClientButton(object sender, RoutedEventArgs e)
    {
        IParentClient newParentClient = new ParentClient();
        newParentClient.SetArguments(new string[] { &quot;&quot;,NewConnectorIdTextBox.Text,&quot;&quot;,&quot;&quot;,&quot;&quot;,&quot;&quot; });
        newParentClient.AttachClient(new WindowInteropHelper(this).Handle);
        ParentClient = newParentClient;
        ParentConnectorId.Text = $&quot;Connector ID: {ParentClient.GetConnectorId()}&quot;;
    }
    

    #endregion ParentClient

    #region ChildClient

    private void StartChildAppButton(object sender, RoutedEventArgs e)
    {
        //ChildClient.StartProcess(&quot;C:\\Users\\iskim\\Downloads\\XG5000_Release_2026_01_07_Bridge\\EngCopilot\\LS.CommonUI.EngSearch.Host.exe&quot;);
        //ChildClient.StartProcess(&quot;D:\\GitLab\\Services\\Extension\\connector\\LS.Extension.Connector\\LS.Extension.Connector.WpfApp\\bin\\x64\\Debug\\net9.0-windows\\LS.Extension.Connector.WpfApp.exe&quot;);
        ChildClient.StartProcess(&quot;D:\\GitLab\\Services\\Extension\\connector\\LS.Extension.Connector\\LS.Extension.Connector.WpfApp\\bin\\x86\\Debug\\net9.0-windows\\LS.Extension.Connector.WpfApp.exe&quot;);
    }

    private void RegisterClient(object? sender, EventArgs e)
    {
        var controlHandle = childWindowHost.GetHostHandle();
        ChildClient.RegisterClient(controlHandle.ToString(), themeName: ThemeName);
        //ChildClient.RegisterClient(themeName: ThemeName);
        ChildConnectorId.Text = $&quot;Connector ID: {ChildClient.GetConnectorId()}&quot;;
    }

    private void SendMessageToChildButton(object sender, RoutedEventArgs e)
    {
        ChildClient.SendMessage(ChildKeyTextBox.Text, ChildMessageTextBox.Text);
    }
    private void GetMessageFromChildButton(object sender, RoutedEventArgs e)
    {
        ChildMessage.Text = ChildClient.GetMessage(ChildKeyTextBox.Text);
    }

    private void SubscribeChildMessageButton(object sender, RoutedEventArgs e)
    {
        var key = ChildKeyTextBox.Text;

        var callback = new MessageCallback((message) =&amp;gt;
        {
            Dispatcher.Invoke(() =&amp;gt;
            {
                ChildMessage.Text = $&quot;[{key}] Received: {message}&quot;;
            });
        });

        ChildClient.SubscribeMessage(key, callback);
    }
    private void NewConnectorButton(object sender, RoutedEventArgs e)
    {
        IChildClient newChildClient = new ChildClient();
        newChildClient.RegisterClient();
        ChildClient = newChildClient;
        NewChildConnectorId.Text = $&quot;/connectorId={ChildClient.GetConnectorId()}&quot;;
        ChildConnectorId.Text = $&quot;Connector ID: {ChildClient.GetConnectorId()}&quot;;
    }
    

    #endregion ChildClient
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ChildWindowHost.cs&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;WPF는 기본적으로 최상위 Root 트리로 Window를 두고 밑으로 UserControl를 두고 있음.&lt;br /&gt;Seamless에 원하는 영역으로 ParentWindowHandle을 주기 위해서 아래와 같이 컨트롤 추가&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MainWindow.xaml&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7kaBQ/dJMcaiJyBSL/nzqukGwk1Aq44QkIPRClEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7kaBQ/dJMcaiJyBSL/nzqukGwk1Aq44QkIPRClEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7kaBQ/dJMcaiJyBSL/nzqukGwk1Aq44QkIPRClEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7kaBQ%2FdJMcaiJyBSL%2FnzqukGwk1Aq44QkIPRClEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;840&quot; height=&quot;148&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1775175418834&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System;
using System.Runtime.InteropServices;
using System.Windows.Interop;

namespace LS.Extension.Connector.WpfApp.Controls;

public class ChildWindowHost : HwndHost
{
    private IntPtr _hwndHost;

    protected override HandleRef BuildWindowCore(HandleRef hwndParent)
    {
        _hwndHost = CreateWindowEx(
            0, &quot;Static&quot;, &quot;&quot;,
            WS_CHILD | WS_VISIBLE,
            0, 0,
            0, 0,
            hwndParent.Handle,
            IntPtr.Zero,
            IntPtr.Zero,
            IntPtr.Zero);

        return new HandleRef(this, _hwndHost);
    }

    protected override void DestroyWindowCore(HandleRef hwnd)
    {
        DestroyWindow(hwnd.Handle);
    }

    public IntPtr GetHostHandle()
    {
        return _hwndHost;
    }

    #region Win32 API

    private const int WS_CHILD = 0x40000000;
    private const int WS_VISIBLE = 0x10000000;

    [DllImport(&quot;user32.dll&quot;, EntryPoint = &quot;CreateWindowEx&quot;, CharSet = CharSet.Unicode)]
    private static extern IntPtr CreateWindowEx(
        int dwExStyle,
        string lpszClassName,
        string lpszWindowName,
        int style,
        int x, int y,
        int width, int height,
        IntPtr hwndParent,
        IntPtr hMenu,
        IntPtr hInst,
        IntPtr pvParam);

    [DllImport(&quot;user32.dll&quot;, EntryPoint = &quot;DestroyWindow&quot;, CharSet = CharSet.Unicode)]
    private static extern bool DestroyWindow(IntPtr hwnd);

    #endregion
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;# MFC&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;594&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkMP57/dJMcacWTXTj/DQ1CMrhhPM58366QSuHWI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkMP57/dJMcacWTXTj/DQ1CMrhhPM58366QSuHWI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkMP57/dJMcacWTXTj/DQ1CMrhhPM58366QSuHWI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkMP57%2FdJMcacWTXTj%2FDQ1CMrhhPM58366QSuHWI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;564&quot; height=&quot;594&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;594&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Contract.dll 로부터 .tlb 파일 얻은 후 .h 파일로 변환.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1146&quot; data-origin-height=&quot;1084&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGKjAX/dJMcaiCOqJz/9vKWPkojvXVpYzxu9ZyLM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGKjAX/dJMcaiCOqJz/9vKWPkojvXVpYzxu9ZyLM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGKjAX/dJMcaiCOqJz/9vKWPkojvXVpYzxu9ZyLM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGKjAX%2FdJMcaiCOqJz%2F9vKWPkojvXVpYzxu9ZyLM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1146&quot; height=&quot;1084&quot; data-origin-width=&quot;1146&quot; data-origin-height=&quot;1084&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1221&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbV5Nx/dJMcagkHlbf/KS5ZhtdN6jkTCZcY1Zz7q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbV5Nx/dJMcagkHlbf/KS5ZhtdN6jkTCZcY1Zz7q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbV5Nx/dJMcagkHlbf/KS5ZhtdN6jkTCZcY1Zz7q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbV5Nx%2FdJMcagkHlbf%2FKS5ZhtdN6jkTCZcY1Zz7q0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1221&quot; height=&quot;297&quot; data-origin-width=&quot;1221&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ezFU1s/dJMcabcB2tG/5k33IlqchOoGb3MG2KppYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ezFU1s/dJMcabcB2tG/5k33IlqchOoGb3MG2KppYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ezFU1s/dJMcabcB2tG/5k33IlqchOoGb3MG2KppYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FezFU1s%2FdJMcabcB2tG%2F5k33IlqchOoGb3MG2KppYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;843&quot; height=&quot;446&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;446&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMjLUD/dJMcai3Qfp5/o34jydOHemEdPDYZzPt6X1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMjLUD/dJMcai3Qfp5/o34jydOHemEdPDYZzPt6X1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMjLUD/dJMcai3Qfp5/o34jydOHemEdPDYZzPt6X1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMjLUD%2FdJMcai3Qfp5%2Fo34jydOHemEdPDYZzPt6X1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;886&quot; height=&quot;610&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;883&quot; data-origin-height=&quot;471&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pMRY7/dJMcabjqUUN/YVyukmBea43V1kTQinr3l0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pMRY7/dJMcabjqUUN/YVyukmBea43V1kTQinr3l0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pMRY7/dJMcabjqUUN/YVyukmBea43V1kTQinr3l0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpMRY7%2FdJMcabjqUUN%2FYVyukmBea43V1kTQinr3l0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;883&quot; height=&quot;471&quot; data-origin-width=&quot;883&quot; data-origin-height=&quot;471&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;895&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxqvaO/dJMcaaY5AkB/RzdpYNgasBsXJwDlsjqV60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxqvaO/dJMcaaY5AkB/RzdpYNgasBsXJwDlsjqV60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxqvaO/dJMcaaY5AkB/RzdpYNgasBsXJwDlsjqV60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdxqvaO%2FdJMcaaY5AkB%2FRzdpYNgasBsXJwDlsjqV60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;895&quot; height=&quot;654&quot; data-origin-width=&quot;895&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1134&quot; data-origin-height=&quot;137&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsR7st/dJMcagSyOcb/rSKATdFJtaVgwuO4aSkqt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsR7st/dJMcagSyOcb/rSKATdFJtaVgwuO4aSkqt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsR7st/dJMcagSyOcb/rSKATdFJtaVgwuO4aSkqt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsR7st%2FdJMcagSyOcb%2FrSKATdFJtaVgwuO4aSkqt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1134&quot; height=&quot;137&quot; data-origin-width=&quot;1134&quot; data-origin-height=&quot;137&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MessageCallbackHandler.h&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;CoCreateFreeThreadedMarshaler 이걸 해줘야&amp;nbsp; .net COM 마샬링 호출이 가능함.&lt;/blockquote&gt;
&lt;pre id=&quot;code_1775176569265&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pragma once

#include &quot;LS.Extension.Connector.Contract.h&quot;
#include &amp;lt;atlbase.h&amp;gt;
#include &amp;lt;atlcom.h&amp;gt;
#include &amp;lt;atomic&amp;gt;
#include &amp;lt;afxwin.h&amp;gt;

// CMessageCallbackHandler class for handling IMessageCallback
class CMessageCallbackHandler : public IMessageCallback
{
public:
    CMessageCallbackHandler(CStatic* pLabelResult) 
        : m_pLabelResult(pLabelResult)
        , m_pFreeThreadedMarshaler(nullptr)
        , m_bInitialized(false)
    {
    }

    // Initialize method to be called after construction
    HRESULT Initialize()
    {
        if (m_bInitialized)
            return S_OK;

        // Create Free-Threaded Marshaler to enable cross-apartment marshaling
        HRESULT hr = CoCreateFreeThreadedMarshaler(static_cast&amp;lt;IMessageCallback*&amp;gt;(this), &amp;amp;m_pFreeThreadedMarshaler);
        if (SUCCEEDED(hr))
        {
            m_bInitialized = true;
        }
        return hr;
    }

    // IMessageCallback method
    STDMETHODIMP OnMessageReceived(BSTR message) override
    {
        if (!message)
            return E_POINTER;

        // Directly convert BSTR to CString without using _bstr_t
        CString strMessage;
        strMessage.Format(_T(&quot;Message received: %s&quot;), CString(message));

        if (m_pLabelResult &amp;amp;&amp;amp; m_pLabelResult-&amp;gt;GetSafeHwnd())
        {
            m_pLabelResult-&amp;gt;SetWindowText(strMessage);
        }

        return S_OK;
    }

    // IUnknown methods
    STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
    {
        if (!ppv) return E_POINTER;

        if (riid == IID_IUnknown || riid == IID_IDispatch || riid == __uuidof(IMessageCallback))
        {
            *ppv = static_cast&amp;lt;IMessageCallback*&amp;gt;(this);
            AddRef();
            return S_OK;
        }

        // Delegate to Free-Threaded Marshaler for IMarshal interface
        if (riid == IID_IMarshal)
        {
            // Lazy initialization of Free-Threaded Marshaler
            if (!m_bInitialized)
            {
                Initialize();
            }

            if (m_pFreeThreadedMarshaler)
            {
                return m_pFreeThreadedMarshaler-&amp;gt;QueryInterface(riid, ppv);
            }
        }

        *ppv = nullptr;
        return E_NOINTERFACE;
    }

    STDMETHODIMP_(ULONG) AddRef() override
    {
        return ++m_refCount;
    }

    STDMETHODIMP_(ULONG) Release() override
    {
        ULONG newCount = --m_refCount;
        if (newCount == 0) delete this;
        return newCount;
    }

    // IDispatch methods (stubs for simplicity)
    STDMETHODIMP GetTypeInfoCount(UINT* pctinfo)
    {
        *pctinfo = 0;
        return S_OK;
    }

    STDMETHODIMP GetTypeInfo(UINT /*iTInfo*/, LCID /*lcid*/, ITypeInfo** /*ppTInfo*/)
    {
        return E_NOTIMPL;
    }

    STDMETHODIMP GetIDsOfNames(REFIID /*riid*/, LPOLESTR* /*rgszNames*/, UINT /*cNames*/, LCID /*lcid*/, DISPID* /*rgDispId*/)
    {
        return E_NOTIMPL;
    }

    STDMETHODIMP Invoke(DISPID /*dispIdMember*/, REFIID /*riid*/, LCID /*lcid*/, WORD /*wFlags*/, DISPPARAMS* /*pDispParams*/, VARIANT* /*pVarResult*/, EXCEPINFO* /*pExcepInfo*/, UINT* /*puArgErr*/)
    {
        return E_NOTIMPL;
    }

private:
    ~CMessageCallbackHandler() 
    {
        if (m_pFreeThreadedMarshaler)
        {
            m_pFreeThreadedMarshaler-&amp;gt;Release();
            m_pFreeThreadedMarshaler = nullptr;
        }
    }

    std::atomic&amp;lt;ULONG&amp;gt; m_refCount{ 1 };
    CStatic* m_pLabelResult;
    IUnknown* m_pFreeThreadedMarshaler;
    bool m_bInitialized;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호출 사용 예시&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;br /&gt;객체 인스턴스 생성&lt;br /&gt;&lt;br /&gt;IChildClient* m_pChildClient;&lt;br /&gt;&lt;br /&gt;HRESULT hr = CoCreateInstance(__uuidof(ChildClientClass), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IChildClient), (void**)&amp;amp;m_pChildClient); &lt;br /&gt;&lt;br /&gt;인터페이스 호출 해서 사용.&lt;br /&gt;m_pChildClient-&amp;gt;RegisterClient(bstrHwnd);&lt;br /&gt;m_pChildClient-&amp;gt;StartProcess(bstrPath); &lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;pre id=&quot;code_1775176748068&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void CLSExtensionConnectorMfcAppDlg::OnBnClickedButton1()
{
	// TODO: Add your control notification handler code here
	CWaitCursor wait;

	CoInitialize(NULL);
	try
	{
		if (m_pChildClient == nullptr)
		{
			HRESULT hr = CoCreateInstance(__uuidof(ChildClientClass), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IChildClient), (void**)&amp;amp;m_pChildClient);

			if (FAILED(hr) || m_pChildClient == nullptr)
			{
				AfxMessageBox(_T(&quot;COM 객체 생성 실패&quot;));
				CoUninitialize();
				return;
			}
		}

		CString strResult;

		BSTR bstrPath = ::SysAllocString(L&quot;D:\\GitLab\\Services\\Extension\\connector\\LS.Extension.Connector\\LS.Extension.Connector.WpfApp\\bin\\x64\\Debug\\net9.0-windows\\LS.Extension.Connector.WpfApp.exe&quot;);
		//BSTR bstrPath = ::SysAllocString(L&quot;C:\\Users\\iskim\\Downloads\\XG5000_Release_2026_01_07_Bridge\\EngCopilot\\LS.CommonUI.EngSearch.Host.exe&quot;);

		HWND rightHwnd = m_wndRight.GetSafeHwnd();
		strResult.Format(L&quot;%d&quot;, (UINT_PTR)rightHwnd);
		BSTR bstrHwnd = ::SysAllocString(strResult);
		m_pChildClient-&amp;gt;RegisterClient(bstrHwnd);
		::SysFreeString(bstrHwnd);

		m_pChildClient-&amp;gt;StartProcess(bstrPath);
		::SysFreeString(bstrPath);

		BSTR bstrKey = ::SysAllocString(L&quot;TestKey&quot;);
		BSTR bstrMsg = ::SysAllocString(L&quot;Hello from MFC Parent Client!&quot;);
		m_pChildClient-&amp;gt;SendMessageW(bstrKey, bstrMsg);
		::SysFreeString(bstrKey);
		::SysFreeString(bstrMsg);
	}
	catch (...)
	{
		AfxMessageBox(_T(&quot;알 수 없는 예외 발생&quot;));
	}

	CoUninitialize();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C#/WPF</category>
      <author>딸기우유중독</author>
      <guid isPermaLink="true">https://dlsenfl.tistory.com/638</guid>
      <comments>https://dlsenfl.tistory.com/entry/WPF%EB%B3%84-Seamless-Messaging-Sample#entry638comment</comments>
      <pubDate>Fri, 3 Apr 2026 09:12:22 +0900</pubDate>
    </item>
    <item>
      <title>[C#] gRPC Proto</title>
      <link>https://dlsenfl.tistory.com/entry/C-gRPC-Proto</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://protobuf.dev/programming-guides/proto3/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://protobuf.dev/programming-guides/proto3/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dictionary&amp;lt;k,v&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2126&quot; data-origin-height=&quot;1805&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eeJhPM/dJMb996OEXa/eDD4GBegddmgoV6GIXCB40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eeJhPM/dJMb996OEXa/eDD4GBegddmgoV6GIXCB40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eeJhPM/dJMb996OEXa/eDD4GBegddmgoV6GIXCB40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeeJhPM%2FdJMb996OEXa%2FeDD4GBegddmgoV6GIXCB40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2126&quot; height=&quot;1805&quot; data-origin-width=&quot;2126&quot; data-origin-height=&quot;1805&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C#/기초</category>
      <author>딸기우유중독</author>
      <guid isPermaLink="true">https://dlsenfl.tistory.com/636</guid>
      <comments>https://dlsenfl.tistory.com/entry/C-gRPC-Proto#entry636comment</comments>
      <pubDate>Mon, 23 Mar 2026 16:50:11 +0900</pubDate>
    </item>
    <item>
      <title>[Blazor] wwwroot</title>
      <link>https://dlsenfl.tistory.com/entry/Blazor-wwwroot</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;925&quot; data-origin-height=&quot;1041&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceDztc/dJMcagralkv/Y5ZngX1v4d1qQICHRkUhu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceDztc/dJMcagralkv/Y5ZngX1v4d1qQICHRkUhu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceDztc/dJMcagralkv/Y5ZngX1v4d1qQICHRkUhu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceDztc%2FdJMcagralkv%2FY5ZngX1v4d1qQICHRkUhu0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;925&quot; height=&quot;1041&quot; data-origin-width=&quot;925&quot; data-origin-height=&quot;1041&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C#/Blazor</category>
      <author>딸기우유중독</author>
      <guid isPermaLink="true">https://dlsenfl.tistory.com/635</guid>
      <comments>https://dlsenfl.tistory.com/entry/Blazor-wwwroot#entry635comment</comments>
      <pubDate>Wed, 11 Mar 2026 11:17:41 +0900</pubDate>
    </item>
    <item>
      <title>[VS] Nuget Package 수동 추가</title>
      <link>https://dlsenfl.tistory.com/entry/VS-Nuget-Package-%EC%88%98%EB%8F%99-%EC%B6%94%EA%B0%80</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지 경로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;D:\PlayGround\WpfApp1\BlazorButtonLib.Wpf\bin\Debug&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/187jM/dJMcac3lGWO/4AMNHeK4jKf7lf2Lw137z0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/187jM/dJMcac3lGWO/4AMNHeK4jKf7lf2Lw137z0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/187jM/dJMcac3lGWO/4AMNHeK4jKf7lf2Lw137z0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F187jM%2FdJMcac3lGWO%2F4AMNHeK4jKf7lf2Lw137z0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1592&quot; height=&quot;474&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가하고자 하는 프로젝트 폴더로 이동 후 아래 명령어 실행.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EX)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1599&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FEBBb/dJMcai3xgGN/kR5EgkpIJZ6CtxSK8Cj1l1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FEBBb/dJMcai3xgGN/kR5EgkpIJZ6CtxSK8Cj1l1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FEBBb/dJMcai3xgGN/kR5EgkpIJZ6CtxSK8Cj1l1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFEBBb%2FdJMcai3xgGN%2FkR5EgkpIJZ6CtxSK8Cj1l1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1599&quot; height=&quot;862&quot; data-origin-width=&quot;1599&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773192241335&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dotnet add package BlazorButtonLib.Wpf --version 1.0.2 --source &quot;D:\PlayGround\WpfApp1\BlazorButtonLib.Wpf\bin\Debug&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;1018&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p5wu7/dJMcahKo2XZ/Ii0CPEKZlEkFRSPR3crH40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p5wu7/dJMcahKo2XZ/Ii0CPEKZlEkFRSPR3crH40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p5wu7/dJMcahKo2XZ/Ii0CPEKZlEkFRSPR3crH40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp5wu7%2FdJMcahKo2XZ%2FIi0CPEKZlEkFRSPR3crH40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;766&quot; height=&quot;1018&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;1018&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qOkcp/dJMcahjlxYX/HOMVOTW5sia4ZDGk92iNJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qOkcp/dJMcahjlxYX/HOMVOTW5sia4ZDGk92iNJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qOkcp/dJMcahjlxYX/HOMVOTW5sia4ZDGk92iNJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqOkcp%2FdJMcahjlxYX%2FHOMVOTW5sia4ZDGk92iNJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;792&quot; height=&quot;192&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;192&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2089&quot; data-origin-height=&quot;337&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YXiA0/dJMcadnDYJt/QeBroKTIhy4bVYOsQFCM2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YXiA0/dJMcadnDYJt/QeBroKTIhy4bVYOsQFCM2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YXiA0/dJMcadnDYJt/QeBroKTIhy4bVYOsQFCM2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYXiA0%2FdJMcadnDYJt%2FQeBroKTIhy4bVYOsQFCM2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2089&quot; height=&quot;337&quot; data-origin-width=&quot;2089&quot; data-origin-height=&quot;337&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Visual Studio</category>
      <author>딸기우유중독</author>
      <guid isPermaLink="true">https://dlsenfl.tistory.com/634</guid>
      <comments>https://dlsenfl.tistory.com/entry/VS-Nuget-Package-%EC%88%98%EB%8F%99-%EC%B6%94%EA%B0%80#entry634comment</comments>
      <pubDate>Wed, 11 Mar 2026 10:28:53 +0900</pubDate>
    </item>
    <item>
      <title>[VS][별*] Github Copilot MCP 사용</title>
      <link>https://dlsenfl.tistory.com/entry/VS%EB%B3%84-Github-Copilot-MCP-%EC%82%AC%EC%9A%A9</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 Github Copilot MCP tools 가 있어야 Agent 모드로 알아서 파일 지지고 볶는 행위를 함.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1257&quot; data-origin-height=&quot;1726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzYak6/dJMcaa5yGUk/31RC3miahlQHDdL37LrnUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzYak6/dJMcaa5yGUk/31RC3miahlQHDdL37LrnUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzYak6/dJMcaa5yGUk/31RC3miahlQHDdL37LrnUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzYak6%2FdJMcaa5yGUk%2F31RC3miahlQHDdL37LrnUk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1257&quot; height=&quot;1726&quot; data-origin-width=&quot;1257&quot; data-origin-height=&quot;1726&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 솔루션 만들면 안들어가있고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마도 Git clone하면 아래처럼 Solution 폴더 안에 .mcp.json으로 생성하는것 같은데 ( 추정. 확인 해봐야 함.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1880&quot; data-origin-height=&quot;1046&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7kelp/dJMcabDo6cP/1ZoFp9pbvqhdqmXTMKiQS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7kelp/dJMcabDo6cP/1ZoFp9pbvqhdqmXTMKiQS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7kelp/dJMcabDo6cP/1ZoFp9pbvqhdqmXTMKiQS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7kelp%2FdJMcabDo6cP%2F1ZoFp9pbvqhdqmXTMKiQS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1880&quot; height=&quot;1046&quot; data-origin-width=&quot;1880&quot; data-origin-height=&quot;1046&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여튼 로컬에서 새로만든 solution 프로젝트에서도 사용하고 싶으면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 폴더에 있는 Global .mcp.json 에 Server 로 추가해 줘야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;937&quot; data-origin-height=&quot;1047&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zGtCM/dJMcaaqXuA0/zY9JapZDi1ONsDLUKx1Bm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zGtCM/dJMcaaqXuA0/zY9JapZDi1ONsDLUKx1Bm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zGtCM/dJMcaaqXuA0/zY9JapZDi1ONsDLUKx1Bm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzGtCM%2FdJMcaaqXuA0%2FzY9JapZDi1ONsDLUKx1Bm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;937&quot; height=&quot;1047&quot; data-origin-width=&quot;937&quot; data-origin-height=&quot;1047&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 처럼 직접 추가해서 수정해주고 저장.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2468&quot; data-origin-height=&quot;1302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgWAAS/dJMcahcw3i7/P9qtXpOXUJd0912vALodjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgWAAS/dJMcahcw3i7/P9qtXpOXUJd0912vALodjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgWAAS/dJMcahcw3i7/P9qtXpOXUJd0912vALodjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgWAAS%2FdJMcahcw3i7%2FP9qtXpOXUJd0912vALodjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2468&quot; height=&quot;1302&quot; data-origin-width=&quot;2468&quot; data-origin-height=&quot;1302&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.mcp.json&lt;/p&gt;
&lt;pre id=&quot;code_1773129427341&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;inputs&quot;: [],
  &quot;servers&quot;: {
 
&quot;github&quot;: {
      &quot;type&quot;: &quot;stdio&quot;,
      &quot;command&quot;: &quot;docker&quot;,
      &quot;args&quot;: [
        &quot;run&quot;,
        &quot;-i&quot;,
        &quot;--rm&quot;,
        &quot;-e&quot;,
        &quot;GITHUB_PERSONAL_ACCESS_TOKEN&quot;,
        &quot;ghcr.io/github/github-mcp-server&quot;
      ],
      &quot;env&quot;: {
        &quot;GITHUB_PERSONAL_ACCESS_TOKEN&quot;: &quot;${input:github_pat}&quot;
      }
    }

  }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Visual Studio</category>
      <author>딸기우유중독</author>
      <guid isPermaLink="true">https://dlsenfl.tistory.com/633</guid>
      <comments>https://dlsenfl.tistory.com/entry/VS%EB%B3%84-Github-Copilot-MCP-%EC%82%AC%EC%9A%A9#entry633comment</comments>
      <pubDate>Tue, 10 Mar 2026 16:44:49 +0900</pubDate>
    </item>
    <item>
      <title>[DX_WPF] AI Chat Control</title>
      <link>https://dlsenfl.tistory.com/entry/DXWPF-AI-Chat-Control</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;view&lt;/p&gt;
&lt;pre id=&quot;code_1766016209778&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;UserControl x:Class=&quot;LS.CommonUI.EngSearch.Com.Views.EngCopilotView&quot;
             xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
             xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
             xmlns:mc=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
             xmlns:d=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;
             xmlns:dxmvvm=&quot;http://schemas.devexpress.com/winfx/2008/xaml/mvvm&quot; 
             xmlns:ViewModels=&quot;clr-namespace:LS.CommonUI.EngSearch.Com.ViewModels&quot; 
             xmlns:dxaichat=&quot;http://schemas.devexpress.com/winfx/2008/xaml/aichat&quot; 
             xmlns:chat=&quot;clr-namespace:DevExpress.AIIntegration.Blazor.Chat;assembly=DevExpress.AIIntegration.Blazor.Chat.v25.2&quot;
             xmlns:system=&quot;clr-namespace:System;assembly=mscorlib&quot;
             mc:Ignorable=&quot;d&quot;
             d:DesignHeight=&quot;300&quot; d:DesignWidth=&quot;600&quot;&amp;gt;
    &amp;lt;Grid&amp;gt;
        &amp;lt;dxaichat:AIChatControl x:Name=&quot;aiChatControl&quot;
            ContentFormat=&quot;Markdown&quot; 
            UseStreaming=&quot;True&quot;
            InputEnabled=&quot;True&quot;
            FileUploadEnabled=&quot;True&quot;
            HorizontalAlignment=&quot;Stretch&quot; 
            VerticalAlignment=&quot;Stretch&quot; 
            Margin=&quot;10&quot;&amp;gt;

            &amp;lt;dxmvvm:Interaction.Behaviors&amp;gt;
                &amp;lt;dxmvvm:EventToCommand 
                        SourceName=&quot;aiChatControl&quot;
                        EventName=&quot;MarkdownConvert&quot; 
                        Command=&quot;{Binding MarkdownConvertCommand}&quot;
                        PassEventArgsToCommand=&quot;True&quot;/&amp;gt;
                &amp;lt;dxmvvm:EventToCommand 
                        SourceName=&quot;aiChatControl&quot;
                        EventName=&quot;MessageSent&quot; 
                        Command=&quot;{Binding MessageSentCommand}&quot;
                        PassEventArgsToCommand=&quot;True&quot;/&amp;gt;
            &amp;lt;/dxmvvm:Interaction.Behaviors&amp;gt;
            
            &amp;lt;dxaichat:AIChatControl.FileUploadSettings&amp;gt;
                &amp;lt;chat:DxAIChatFileUploadSettings MaxFileSize=&quot;5000000&quot; MaxFileCount=&quot;5&quot;&amp;gt;
                    &amp;lt;chat:DxAIChatFileUploadSettings.AllowedFileExtensions&amp;gt;
                        &amp;lt;system:String&amp;gt;.png&amp;lt;/system:String&amp;gt;
                        &amp;lt;system:String&amp;gt;.pdf&amp;lt;/system:String&amp;gt;
                        &amp;lt;system:String&amp;gt;.txt&amp;lt;/system:String&amp;gt;
                    &amp;lt;/chat:DxAIChatFileUploadSettings.AllowedFileExtensions&amp;gt;
                    &amp;lt;chat:DxAIChatFileUploadSettings.FileTypeFilter&amp;gt;
                        &amp;lt;system:String&amp;gt;image/png&amp;lt;/system:String&amp;gt;
                        &amp;lt;system:String&amp;gt;application/pdf&amp;lt;/system:String&amp;gt;
                        &amp;lt;system:String&amp;gt;text/plain&amp;lt;/system:String&amp;gt;
                    &amp;lt;/chat:DxAIChatFileUploadSettings.FileTypeFilter&amp;gt;
                &amp;lt;/chat:DxAIChatFileUploadSettings&amp;gt;
            &amp;lt;/dxaichat:AIChatControl.FileUploadSettings&amp;gt;
            &amp;lt;dxaichat:AIChatControl.PromptSuggestions&amp;gt;
                &amp;lt;chat:DxAIChatPromptSuggestion
            Title=&quot;Birthday Wish&quot;
            Text=&quot;A warm and cheerful birthday greeting message.&quot;
            PromptMessage=&quot;Write a heartfelt birthday message for a close friend.&quot; /&amp;gt;
                &amp;lt;chat:DxAIChatPromptSuggestion
            Title=&quot;Thank You Note&quot;
            Text=&quot;A polite thank you note to express gratitude.&quot;
            PromptMessage=&quot;Compose a short thank you note to a colleague who helped with a project.&quot; /&amp;gt;
            &amp;lt;/dxaichat:AIChatControl.PromptSuggestions&amp;gt;
        &amp;lt;/dxaichat:AIChatControl&amp;gt;
    &amp;lt;/Grid&amp;gt;
&amp;lt;/UserControl&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;viewModel&lt;/p&gt;
&lt;pre id=&quot;code_1766016232704&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using Azure.AI.OpenAI;
using DevExpress.AIIntegration;
using DevExpress.AIIntegration.Blazor.Chat.WebView;
using DevExpress.Data.Utils;
using DevExpress.Mvvm;
using LS.CommonUI.EngSearch.Com.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Client;
using OpenAI.Chat;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
using ChatMessage = Microsoft.Extensions.AI.ChatMessage;

namespace LS.CommonUI.EngSearch.Com.ViewModels;

public class EngCopilotViewModel : ViewModelBase
{
    public string Header { get; set; } = &quot;XGPilot&quot;;
    IChatClient asChatClient = null;
    List&amp;lt;Microsoft.Extensions.AI.ChatMessage&amp;gt; messages = [];

    public EngCopilotViewModel()
    {
        RegisterAIChatClient();
        //var tools = GetMCPToolTest();
        //ApplyToolsToChatClient();

       
    }

    private DelegateCommand&amp;lt;object&amp;gt; markdownConvertCommand;
    public DelegateCommand&amp;lt;object&amp;gt; MarkdownConvertCommand =&amp;gt;
        markdownConvertCommand ?? (markdownConvertCommand = new DelegateCommand&amp;lt;object&amp;gt;(ExecuteMarkdownConvertCommand));
    void ExecuteMarkdownConvertCommand(object obj)
    {
        var e = obj as AIChatControlMarkdownConvertEventArgs;
        e.HtmlText = (MarkupString)Markdig.Markdown.ToHtml(e.MarkdownText);
    }

    private DelegateCommand&amp;lt;object&amp;gt; messageSentCommand;
    public DelegateCommand&amp;lt;object&amp;gt; MessageSentCommand =&amp;gt;
        messageSentCommand ?? (messageSentCommand = new DelegateCommand&amp;lt;object&amp;gt;(ExecuteMessageSentCommand));
    async void ExecuteMessageSentCommand(object obj)
    {
        var e = obj as AIChatControlMessageSentEventArgs;
        var message = e.Content;

        var messages = await ApplyToolsToChatClient(message, e);

        //await e.SendMessage(, ChatRole.Assistant);
    }



    async Task&amp;lt;IList&amp;lt;McpClientTool&amp;gt;&amp;gt; GetMCPToolTest()
    {
        var client = McpClientCollection.GetAxMcpClient();
        var tools = await client.ListToolsAsync();
        return tools;
    }


    async Task&amp;lt;List&amp;lt;ChatMessage&amp;gt;&amp;gt; ApplyToolsToChatClient(string message, AIChatControlMessageSentEventArgs eventArgs)
    {
        //Console.Write(&quot;Q: &quot;);
        messages.Add(new(ChatRole.User, message));

        List&amp;lt;ChatResponseUpdate&amp;gt; updates = [];
        string updateText = string.Empty;
        var tools = await GetMCPToolTest();
        await foreach (var update in asChatClient.GetStreamingResponseAsync(messages, new() { Tools = [.. tools] }))
        {
            updateText += update.Text;
            updates.Add(update);
        }
        await eventArgs.SendMessage(updateText, ChatRole.Assistant);

        //messages.Clear();
        messages.AddMessages(updates);
        return Task.FromResult(messages).Result;
    }

    private void RegisterAIChatClient()
    {
        string azureOpenAIEndpoint = &quot;https://iskimls.openai.azure.com/&quot;;
        string azureOpenAIKey = &quot;3XP9Nm6azrubLH0LTc8UmMvpZcVRYFTGF4rO1ywWhb4QQxlWGsQiJQQJ99BLACHYHv6XJ3w3AAABACOGjeb3&quot;;
        string deployment = &quot;gpt-5-chat&quot;;

        var container = AIExtensionsContainerDesktop.Default;

        asChatClient = new ChatClientBuilder( 
            new AzureOpenAIClient(new Uri(azureOpenAIEndpoint),
                new System.ClientModel.ApiKeyCredential(azureOpenAIKey))
            .GetChatClient(deployment).AsIChatClient() 
            ).UseDXTools()
            .UseFunctionInvocation()
            .Build(container);

        container.RegisterChatClient(asChatClient);

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;asChatClient = new ChatClientBuilder( ... )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ChatClientBuilder 사용해야 GetStreamingResponseAsync 에서 오류 안남.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;# MessageSent&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1766040496721&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  &amp;lt;dxmvvm:EventToCommand 
          SourceName=&quot;aiChatControl&quot;
          EventName=&quot;MessageSent&quot; 
          Command=&quot;{Binding MessageSentCommand}&quot;
          PassEventArgsToCommand=&quot;True&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1766040487634&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;
    private DelegateCommand&amp;lt;object&amp;gt; messageSentCommand;
    public DelegateCommand&amp;lt;object&amp;gt; MessageSentCommand =&amp;gt;
        messageSentCommand ?? (messageSentCommand = new DelegateCommand&amp;lt;object&amp;gt;(ExecuteMessageSentCommand));
    async void ExecuteMessageSentCommand(object obj)
    {
        var e = obj as AIChatControlMessageSentEventArgs;
        var message = e.Content;

        var messages = await ApplyToolsToChatClient(message, e);

    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI Chat Control에서 prompt 입력시 Message를 기존 DevExpress 로직이 아니라 Custom 해서 Reply 가능하게 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# 직접 Reply를 얻어서 반환해줘야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;MessageSent 사용시 기존 AIChatControl과의 호환성 문제 있음.&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ex) ChatResources 적용 안된다던가..&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.devexpress.com/WPF/405434/ai-powered-extensions/ai-chat-control?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946#tool-calling&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.devexpress.com/WPF/405434/ai-powered-extensions/ai-chat-control?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946#tool-calling&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1766016175322&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;AI Chat Control | WPF Controls | DevExpress Documentation&quot; data-og-description=&quot;Developer documentation for all DevExpress products.&quot; data-og-host=&quot;docs.devexpress.com&quot; data-og-source-url=&quot;https://docs.devexpress.com/WPF/405434/ai-powered-extensions/ai-chat-control?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946#tool-calling&quot; data-og-url=&quot;https://docs.devexpress.com/WPF/405434/ai-powered-extensions/ai-chat-control&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d4taOk/hyZPpzdOae/Op0alT6C4im533ajpxk2F1/img.png?width=1152&amp;amp;height=1007&amp;amp;face=0_0_1152_1007,https://scrap.kakaocdn.net/dn/bAXgLQ/hyZPZFITi9/whzsQegbm3s4EUZay8flpk/img.png?width=954&amp;amp;height=942&amp;amp;face=0_0_954_942,https://scrap.kakaocdn.net/dn/1LpZe/hyZPx47ekT/pUCHwDky0nDaZleqMJvkIk/img.png?width=764&amp;amp;height=830&amp;amp;face=0_0_764_830&quot;&gt;&lt;a href=&quot;https://docs.devexpress.com/WPF/405434/ai-powered-extensions/ai-chat-control?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946#tool-calling&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.devexpress.com/WPF/405434/ai-powered-extensions/ai-chat-control?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946#tool-calling&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d4taOk/hyZPpzdOae/Op0alT6C4im533ajpxk2F1/img.png?width=1152&amp;amp;height=1007&amp;amp;face=0_0_1152_1007,https://scrap.kakaocdn.net/dn/bAXgLQ/hyZPZFITi9/whzsQegbm3s4EUZay8flpk/img.png?width=954&amp;amp;height=942&amp;amp;face=0_0_954_942,https://scrap.kakaocdn.net/dn/1LpZe/hyZPx47ekT/pUCHwDky0nDaZleqMJvkIk/img.png?width=764&amp;amp;height=830&amp;amp;face=0_0_764_830');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;AI Chat Control | WPF Controls | DevExpress Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Developer documentation for all DevExpress products.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.devexpress.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.devexpress.com/WPF/405613/ai-powered-extensions/ai-chat-control/resources?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.devexpress.com/WPF/405613/ai-powered-extensions/ai-chat-control/resources?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1766041380317&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Chat Resources | WPF Controls | DevExpress Documentation&quot; data-og-description=&quot;Developer documentation for all DevExpress products.&quot; data-og-host=&quot;docs.devexpress.com&quot; data-og-source-url=&quot;https://docs.devexpress.com/WPF/405613/ai-powered-extensions/ai-chat-control/resources?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946&quot; data-og-url=&quot;https://docs.devexpress.com/WPF/405613/ai-powered-extensions/ai-chat-control/resources&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bLz4g9/hyZPULeopb/4kkqXCRHbwNTOS2ODPbGk1/img.png?width=430&amp;amp;height=542&amp;amp;face=0_0_430_542&quot;&gt;&lt;a href=&quot;https://docs.devexpress.com/WPF/405613/ai-powered-extensions/ai-chat-control/resources?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.devexpress.com/WPF/405613/ai-powered-extensions/ai-chat-control/resources?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bLz4g9/hyZPULeopb/4kkqXCRHbwNTOS2ODPbGk1/img.png?width=430&amp;amp;height=542&amp;amp;face=0_0_430_542');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Chat Resources | WPF Controls | DevExpress Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Developer documentation for all DevExpress products.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.devexpress.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.devexpress.com/CoreLibraries/405585/ai-integration/ai-tool-calling?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.devexpress.com/CoreLibraries/405585/ai-integration/ai-tool-calling?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1766041354720&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Tool Calling (AI Chat Control) | Cross-Platform Class Library | DevExpress Documentation&quot; data-og-description=&quot;Developer documentation for all DevExpress products.&quot; data-og-host=&quot;docs.devexpress.com&quot; data-og-source-url=&quot;https://docs.devexpress.com/CoreLibraries/405585/ai-integration/ai-tool-calling?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946&quot; data-og-url=&quot;https://docs.devexpress.com/CoreLibraries/405585/ai-integration/ai-tool-calling&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/A8W58/hyZPCFo9Rk/QjwqPKID3VAUBnKUZMRK2K/img.png?width=490&amp;amp;height=600&amp;amp;face=0_0_490_600&quot;&gt;&lt;a href=&quot;https://docs.devexpress.com/CoreLibraries/405585/ai-integration/ai-tool-calling?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.devexpress.com/CoreLibraries/405585/ai-integration/ai-tool-calling?v=25.2&amp;amp;utm_source=SupportCenter&amp;amp;utm_medium=mail&amp;amp;utm_campaign=docs-feedback&amp;amp;utm_content=T1316946&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/A8W58/hyZPCFo9Rk/QjwqPKID3VAUBnKUZMRK2K/img.png?width=490&amp;amp;height=600&amp;amp;face=0_0_490_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Tool Calling (AI Chat Control) | Cross-Platform Class Library | DevExpress Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Developer documentation for all DevExpress products.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.devexpress.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevExpress/DX_WPF</category>
      <author>딸기우유중독</author>
      <guid isPermaLink="true">https://dlsenfl.tistory.com/632</guid>
      <comments>https://dlsenfl.tistory.com/entry/DXWPF-AI-Chat-Control#entry632comment</comments>
      <pubDate>Thu, 18 Dec 2025 09:03:05 +0900</pubDate>
    </item>
    <item>
      <title>[VS] build bug, Error</title>
      <link>https://dlsenfl.tistory.com/entry/VS-build-bug-Error</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# Visual Studio 에서 git branch 바꾸면서 build시 빌드결과물이 제대로 안나오는 버그있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ex)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A패키지 포함하는 브랜치 빌드 후&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A패키지 포함하지 않는 브랜치 넘어와서 빌드 시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A패키지 포함되어서 빌드되는 경우.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# Sol&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VS 재시작.&lt;/p&gt;</description>
      <category>Visual Studio</category>
      <author>딸기우유중독</author>
      <guid isPermaLink="true">https://dlsenfl.tistory.com/631</guid>
      <comments>https://dlsenfl.tistory.com/entry/VS-build-bug-Error#entry631comment</comments>
      <pubDate>Mon, 15 Dec 2025 11:39:17 +0900</pubDate>
    </item>
    <item>
      <title>[C#] HttpClient</title>
      <link>https://dlsenfl.tistory.com/entry/C-HttpClient</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;# Error&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://keistory.tistory.com/1735&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://keistory.tistory.com/1735&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The&amp;nbsp;SSL&amp;nbsp;connection&amp;nbsp;could&amp;nbsp;not&amp;nbsp;be&amp;nbsp;established,&amp;nbsp;see&amp;nbsp;inner&amp;nbsp;exception&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1765262699920&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =&amp;gt; { return true; };
HttpClient httpClient = new HttpClient(clientHandler);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ex)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;McpClient 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1778&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wwwLW/dJMcadAtzo2/qoBAHkQwnaLh4pcvtKDKLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wwwLW/dJMcadAtzo2/qoBAHkQwnaLh4pcvtKDKLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wwwLW/dJMcadAtzo2/qoBAHkQwnaLh4pcvtKDKLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwwwLW%2FdJMcadAtzo2%2FqoBAHkQwnaLh4pcvtKDKLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1778&quot; height=&quot;880&quot; data-origin-width=&quot;1778&quot; data-origin-height=&quot;880&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C#/기초</category>
      <author>딸기우유중독</author>
      <guid isPermaLink="true">https://dlsenfl.tistory.com/630</guid>
      <comments>https://dlsenfl.tistory.com/entry/C-HttpClient#entry630comment</comments>
      <pubDate>Tue, 9 Dec 2025 15:45:43 +0900</pubDate>
    </item>
    <item>
      <title>[WPF] Http Server</title>
      <link>https://dlsenfl.tistory.com/entry/WPF-Http-Server</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1147&quot; data-origin-height=&quot;591&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjd3HM/dJMcacVR8Ec/d264kDJUCNr4OdXweCKW9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjd3HM/dJMcacVR8Ec/d264kDJUCNr4OdXweCKW9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjd3HM/dJMcacVR8Ec/d264kDJUCNr4OdXweCKW9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbjd3HM%2FdJMcacVR8Ec%2Fd264kDJUCNr4OdXweCKW9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1147&quot; height=&quot;591&quot; data-origin-width=&quot;1147&quot; data-origin-height=&quot;591&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgqyQu/dJMcacau1kU/51pM3UcorlfTDSY22aPkVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgqyQu/dJMcacau1kU/51pM3UcorlfTDSY22aPkVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgqyQu/dJMcacau1kU/51pM3UcorlfTDSY22aPkVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgqyQu%2FdJMcacau1kU%2F51pM3UcorlfTDSY22aPkVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1158&quot; height=&quot;634&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hwanstory.kr/@kim-hwan/posts/run-a-simple-http-web-server-in-dotnet-wpf&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hwanstory.kr/@kim-hwan/posts/run-a-simple-http-web-server-in-dotnet-wpf&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1764547545006&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;.Net WPF 에서 간단하게 Http 웹서버 실행하기&quot; data-og-description=&quot;.Net8 WPF 윈도우 응용프로그램에서 Http 웹서버 기능을 제공하기 위해 여러가지 간단한 Http 구현체를 사용할 수 있다.&quot; data-og-host=&quot;hwanstory.kr&quot; data-og-source-url=&quot;https://hwanstory.kr/@kim-hwan/posts/run-a-simple-http-web-server-in-dotnet-wpf&quot; data-og-url=&quot;https://hwanstory.kr/@kim-hwan/posts/run-a-simple-http-web-server-in-dotnet-wpf&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/n0Yep/hyZOpl4cle/OIPXeRsQZcfNGTC0lsr3F1/img.png?width=788&amp;amp;height=444&amp;amp;face=0_0_788_444,https://scrap.kakaocdn.net/dn/j8X10/hyZO57lkOo/x2ByxGTpnp2IKEz7gJNmpk/img.png?width=788&amp;amp;height=444&amp;amp;face=0_0_788_444&quot;&gt;&lt;a href=&quot;https://hwanstory.kr/@kim-hwan/posts/run-a-simple-http-web-server-in-dotnet-wpf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hwanstory.kr/@kim-hwan/posts/run-a-simple-http-web-server-in-dotnet-wpf&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/n0Yep/hyZOpl4cle/OIPXeRsQZcfNGTC0lsr3F1/img.png?width=788&amp;amp;height=444&amp;amp;face=0_0_788_444,https://scrap.kakaocdn.net/dn/j8X10/hyZO57lkOo/x2ByxGTpnp2IKEz7gJNmpk/img.png?width=788&amp;amp;height=444&amp;amp;face=0_0_788_444');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;.Net WPF 에서 간단하게 Http 웹서버 실행하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;.Net8 WPF 윈도우 응용프로그램에서 Http 웹서버 기능을 제공하기 위해 여러가지 간단한 Http 구현체를 사용할 수 있다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hwanstory.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C#/WPF</category>
      <author>딸기우유중독</author>
      <guid isPermaLink="true">https://dlsenfl.tistory.com/627</guid>
      <comments>https://dlsenfl.tistory.com/entry/WPF-Http-Server#entry627comment</comments>
      <pubDate>Mon, 1 Dec 2025 09:05:51 +0900</pubDate>
    </item>
    <item>
      <title>[AI] IChatClient</title>
      <link>https://dlsenfl.tistory.com/entry/AI-IChatClient</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/agent-framework/user-guide/agents/agent-types/chat-client-agent?pivots=programming-language-csharp&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learn.microsoft.com/ko-kr/agent-framework/user-guide/agents/agent-types/chat-client-agent?pivots=programming-language-csharp&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1764122244880&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;어떤 IChatClient을/를 기반으로 한 에이전트&quot; data-og-description=&quot;IChatClient 구현에서 Microsoft 에이전트 프레임워크를 사용하는 방법을 알아봅니다.&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/ko-kr/agent-framework/user-guide/agents/agent-types/chat-client-agent?pivots=programming-language-csharp&quot; data-og-url=&quot;https://learn.microsoft.com/ko-kr/agent-framework/user-guide/agents/agent-types/chat-client-agent&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/deShzn/hyZOAlJWub/YGdKWD90ob79Xb7H6TJJ5K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/agent-framework/user-guide/agents/agent-types/chat-client-agent?pivots=programming-language-csharp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/ko-kr/agent-framework/user-guide/agents/agent-types/chat-client-agent?pivots=programming-language-csharp&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/deShzn/hyZOAlJWub/YGdKWD90ob79Xb7H6TJJ5K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;어떤 IChatClient을/를 기반으로 한 에이전트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;IChatClient 구현에서 Microsoft 에이전트 프레임워크를 사용하는 방법을 알아봅니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/dotnet/ai/quickstarts/build-mcp-client&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learn.microsoft.com/ko-kr/dotnet/ai/quickstarts/build-mcp-client&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1764122260211&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;빠른 시작 - .NET을 사용하여 최소 MCP 클라이언트 만들기 - .NET&quot; data-og-description=&quot;최소 MCP 클라이언트를 만들고 .NET을 사용하여 MCP 서버에 연결하는 방법을 알아봅니다.&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/ko-kr/dotnet/ai/quickstarts/build-mcp-client&quot; data-og-url=&quot;https://learn.microsoft.com/ko-kr/dotnet/ai/quickstarts/build-mcp-client&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qKnEi/hyZNEcexaA/kS9DhizbW4ojp0i2vsEXv1/img.png?width=456&amp;amp;height=456&amp;amp;face=0_0_456_456&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/dotnet/ai/quickstarts/build-mcp-client&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/ko-kr/dotnet/ai/quickstarts/build-mcp-client&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qKnEi/hyZNEcexaA/kS9DhizbW4ojp0i2vsEXv1/img.png?width=456&amp;amp;height=456&amp;amp;face=0_0_456_456');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;빠른 시작 - .NET을 사용하여 최소 MCP 클라이언트 만들기 - .NET&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;최소 MCP 클라이언트를 만들고 .NET을 사용하여 MCP 서버에 연결하는 방법을 알아봅니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AI</category>
      <author>딸기우유중독</author>
      <guid isPermaLink="true">https://dlsenfl.tistory.com/626</guid>
      <comments>https://dlsenfl.tistory.com/entry/AI-IChatClient#entry626comment</comments>
      <pubDate>Wed, 26 Nov 2025 10:57:45 +0900</pubDate>
    </item>
  </channel>
</rss>