<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dmitry</title>
    <description>The latest articles on DEV Community by Dmitry (@dmitrat).</description>
    <link>https://dev.to/dmitrat</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2236586%2Fba144592-5697-4d47-98c7-1ba16ae77585.png</url>
      <title>DEV Community: Dmitry</title>
      <link>https://dev.to/dmitrat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dmitrat"/>
    <language>en</language>
    <item>
      <title>WitCom and Discovery</title>
      <dc:creator>Dmitry</dc:creator>
      <pubDate>Mon, 03 Mar 2025 15:04:46 +0000</pubDate>
      <link>https://dev.to/dmitrat/witcom-and-discovery-40m3</link>
      <guid>https://dev.to/dmitrat/witcom-and-discovery-40m3</guid>
      <description>&lt;p&gt;As discussed in previous articles, &lt;a href="https://github.com/dmitrat/WitCom/" rel="noopener noreferrer"&gt;WitCom&lt;/a&gt; is inspired by WCF—not necessarily in its internal implementation, but in terms of developer experience and capabilities. One of the key technologies that WCF offered “out of the box” was Discovery. With Discovery, a server could announce its presence on a local network via UDP multicast, allowing clients to learn about available services and decide whether to connect. &lt;a href="https://github.com/dmitrat/WitCom/" rel="noopener noreferrer"&gt;WitCom &lt;/a&gt; offers a similar feature, enhancing flexibility in dynamic environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server-Side Discovery
&lt;/h2&gt;

&lt;p&gt;To enable Discovery during server creation, simply include the appropriate option when building your WitCom server. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var server = WitComServerBuilder.Build(options =&amp;gt;
{
    options.WithService(ExampleService);
    options.WithNamedPipe(address);
    options.WithEncryption();
    options.WithJson();
    options.WithDiscovery();
    options.WithAccessToken(ACCESS_TOKEN);
    options.WithTimeout(TimeSpan.FromSeconds(1));
    options.WithName(dialog.ServerName);
    options.WithDescription(dialog.ServerDescription);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, if you do not specify custom parameters, a one-time “Hello” message is sent at server startup and a “Goodbye” message when it shuts down. These messages are broadcast to the standard multicast address &lt;strong&gt;239.255.255.250&lt;/strong&gt; and port &lt;strong&gt;3702&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can also customize the Discovery parameters:&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Address and Port
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;options.WithDiscovery(host, port);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Periodic Announcements
&lt;/h3&gt;

&lt;p&gt;To continuously remind clients that the server is still available, you can specify a repeat interval:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;options.WithDiscovery(host, port, TimeSpan.FromSeconds(10));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;options.WithDiscovery(TimeSpan.FromSeconds(10));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, while the server is running and accepting connections, a Discovery message is sent every 10 seconds.&lt;/p&gt;

&lt;p&gt;The Discovery message contains critical information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The transport type and connection settings (for example, the name of the memory-mapped file, the named pipe, the TCP port, or the WebSocket URL).&lt;/li&gt;
&lt;li&gt;The server’s name and description (if provided during initialization).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Client-Side Discovery
&lt;/h2&gt;

&lt;p&gt;On the client side, to receive Discovery messages, you need to create a Discovery client. For instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DiscoveryClient = WitComClientBuilder.Discovery(options =&amp;gt;
{
    options.WithLogger(Logger);
    options.WithJson();
    options.WithAddress(host, port);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note: Ensure that you specify the same serializer as on the server (JSON is used by default). If no address is provided, the default multicast address (239.255.255.250) and port (3702) are used.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, subscribe to the event that is fired upon receiving a Discovery message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DiscoveryClient.MessageReceived += OnMessageReceived;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then start listening:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DiscoveryClient.Start();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once a Discovery message is received, you can build a WitCom client by selecting the appropriate transport based on the content of the message. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var client = WitComClientBuilder.Build(options =&amp;gt;
{
    options.WithTransport(SelectedMessage);
    options.WithEncryption();
    options.WithJson();
    options.WithAccessToken(ACCESS_TOKEN);
    options.WithLogger(Logger);
    options.WithTimeout(TimeSpan.FromSeconds(1));
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s an example helper method that configures the transport according to the Discovery message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static WitComClientBuilderOptions WithTransport(this WitComClientBuilderOptions me, DiscoveryMessage message)
{
    if (message.Data == null)
        throw new ArgumentOutOfRangeException(nameof(me), me, null);

    if (message.IsMemoryMappedFile())
        return me.WithMemoryMappedFile(message);

    if (message.IsNamedPipe())
        return me.WithNamedPipe(message);

    if (message.IsTcp())
        return me.WithTcp("localhost", message);

    if (message.IsWebSocket())
        return me.WithWebSocket("ws://localhost", message);

    throw new ArgumentOutOfRangeException(nameof(me), me, null);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Examples and Further Resources
&lt;/h2&gt;

&lt;p&gt;You can find detailed examples of using Discovery with WitCom on GitHub: &lt;a href="https://github.com/dmitrat/WitCom/tree/main/Examples/Discovery" rel="noopener noreferrer"&gt;WitCom Discovery Examples&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  References and Resources
&lt;/h3&gt;

&lt;p&gt;For more in-depth information on WitCom, please refer to the following resources:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ratner.io/witcom/" rel="noopener noreferrer"&gt;WitCom Overview&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ratner.io/2025/01/27/witcom-and-blazor-webassembly/" rel="noopener noreferrer"&gt;WitCom and Blazor WebAssembly&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ratner.io/2025/01/11/witcom-dynamic-proxy-vs-static-proxy/" rel="noopener noreferrer"&gt;WitCom and Static Proxy&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ratner.io/2025/01/05/inter-process-communication-with-witcom/" rel="noopener noreferrer"&gt;Inter-process Communication with WitCom&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/dmitrat/WitCom" rel="noopener noreferrer"&gt;WitCom Project Root&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>programming</category>
      <category>backenddevelopment</category>
      <category>remote</category>
    </item>
    <item>
      <title>Inter-process Communication with WitCom</title>
      <dc:creator>Dmitry</dc:creator>
      <pubDate>Mon, 13 Jan 2025 10:47:45 +0000</pubDate>
      <link>https://dev.to/dmitrat/inter-process-communication-with-witcom-8pc</link>
      <guid>https://dev.to/dmitrat/inter-process-communication-with-witcom-8pc</guid>
      <description>&lt;p&gt;Working on engineering systems that often involve legacy components, I frequently face challenges in integrating outdated elements with modern platforms. For example, you may encounter scenarios requiring support for obsolete file formats that can only be opened by a 32-bit component. This limitation poses a dilemma: either remain on an outdated platform, foregoing modern framework advantages like 64-bit addressing, or isolate the legacy component’s logic into a separate process with which the main application communicates.&lt;/p&gt;

&lt;p&gt;There are numerous scenarios for inter-process communication (IPC) on the same machine, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supporting components built for a different platform than the main system.&lt;/li&gt;
&lt;li&gt;Running multiple parallel, independent processes to overcome system limitations.&lt;/li&gt;
&lt;li&gt;Enabling data exchange between several concurrently running applications.
Many others.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why WitCom?
&lt;/h2&gt;

&lt;p&gt;For years, I relied on WCF for its flexibility, particularly its support for selecting optimized transports like named pipes for local interactions. However, WCF was no longer fully available when I migrated to .NET Core. While recent .NET versions have reintroduced support for WCF, its current status remains uncertain.&lt;/p&gt;

&lt;p&gt;One of WCF’s standout features was ServiceContract, which allows defining a service interface. This approach simplifies development: a client integrating a WCF service generates the required wrapper code automatically, eliminating guesswork about function names or parameters. Unfortunately, both SignalR and gRPC require method calls using plain text method names, complicating code maintenance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter WitCom
&lt;/h2&gt;

&lt;p&gt;A few years ago, I discovered the &lt;a href="https://github.com/jacqueskang/IpcServiceFramework" rel="noopener noreferrer"&gt;IpcServiceFramework&lt;/a&gt;, which uses interfaces to define services and leverages reflection to unpack and invoke methods on the service side. While promising, the project was no longer maintained. Inspired by its core concept, I developed my own implementation, which evolved into WitCom.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ratner.io/witcom/" rel="noopener noreferrer"&gt;WitCom&lt;/a&gt; is a WCF-like communication framework designed for .NET. It enables developers to define service interfaces, choose a transport, and establish full-duplex communication with minimal effort. Supported transports include common options like Named Pipes, TCP, and WebSocket, as well as unique support for memory-mapped files. This enables ultra-fast, low-latency duplex communication on a local machine, ideal for transferring large volumes of data with maximum efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Inter-process Communication with WitCom
&lt;/h2&gt;

&lt;p&gt;You can find an example implementation in the &lt;a href="https://github.com/dmitrat/WitCom/tree/main/Examples/InterProcess" rel="noopener noreferrer"&gt;WitCom GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Define the Service Contract
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface IExampleService
{
    event ExampleServiceEventHandler ProcessingStarted;
    event ExampleServiceProgressEventHandler ProgressChanged;
    event ExampleServiceProcessingEventHandler ProcessingCompleted;

    bool StartProcessing();
    void StopProcessing();
}

public delegate void ExampleServiceEventHandler();
public delegate void ExampleServiceProgressEventHandler(double progress);
public delegate void ExampleServiceProcessingEventHandler(ProcessingStatus status);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WitCom supports full-duplex communication natively using event callbacks, with any delegate type (e.g., &lt;code&gt;PropertyChangedEventHandler&lt;/code&gt;) supported.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Implement the Service in the Agent
&lt;/h3&gt;

&lt;p&gt;The agent process hosts the service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ExampleService : IExampleService
{
    public event ExampleServiceEventHandler ProcessingStarted = delegate { };
    public event ExampleServiceProgressEventHandler ProgressChanged = delegate { };
    public event ExampleServiceProcessingEventHandler ProcessingCompleted = delegate { };

    private CancellationTokenSource? CancellationTokenSource { get; set; }

    public bool StartProcessing()
    {
        if (CancellationTokenSource != null) return false;

        CancellationTokenSource = new CancellationTokenSource();
        Task.Run(Process);

        ProcessingStarted();
        return true;
    }

    public void StopProcessing()
    {
        CancellationTokenSource?.Cancel();
    }

    private void Process()
    {
        ProcessingStatus status = ProcessingStatus.Success;
        for (int i = 1; i &amp;lt;= 100; i++)
        {
            if (CancellationTokenSource?.IsCancellationRequested == true)
            {
                status = ProcessingStatus.Interrupted;
                break;
            }
            ProgressChanged(i);
            Thread.Sleep(100);
        }

        ProcessingCompleted(status);
        CancellationTokenSource = null;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Start the Agent Process
&lt;/h3&gt;

&lt;p&gt;The host process launches the agent as a separate process, passing the communication address via command-line arguments. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var process = new Process
{
    StartInfo = new ProcessStartInfo
    {
        FileName = "Agent.exe",
        Arguments = "--address=ExampleMemoryMap",
        UseShellExecute = false,
    }
};
process.Start();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Start the Server in the Agent
&lt;/h3&gt;

&lt;p&gt;The agent starts the server and listens for connections using the received address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var server = WitComServerBuilder.Build(options =&amp;gt;
{
    options.WithService(new ExampleService());
    options.WithMemoryMappedFile("ExampleMemoryMap");
    options.WithEncryption();
    options.WithJson();
    options.WithAccessToken("SecureAccessToken");
    options.WithTimeout(TimeSpan.FromSeconds(1));
});
server.StartWaitingForConnection();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Create the Client in the Host
&lt;/h3&gt;

&lt;p&gt;The host process connects to the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var client = WitComClientBuilder.Build(options =&amp;gt;
{
    options.WithMemoryMappedFile("ExampleMemoryMap");
    options.WithEncryption();
    options.WithJson();
    options.WithAccessToken("SecureAccessToken");
    options.WithTimeout(TimeSpan.FromSeconds(1));
});

if (!await client.ConnectAsync(TimeSpan.FromSeconds(5), CancellationToken.None))
{
    Console.WriteLine("Failed to connect.");
    return;
}

var service = client.GetService&amp;lt;IExampleService&amp;gt;();
service.ProcessingStarted += () =&amp;gt; Console.WriteLine("Processing started!");
service.ProgressChanged += progress =&amp;gt; Console.WriteLine($"Progress: {progress}%");
service.ProcessingCompleted += status =&amp;gt; Console.WriteLine($"Processing completed: {status}");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Advantages of WitCom
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Service Contracts: Define service interfaces for a clean and maintainable API.&lt;/li&gt;
&lt;li&gt;Multiple Transports: Choose from Named Pipes, TCP, WebSocket, or memory-mapped files.&lt;/li&gt;
&lt;li&gt;Full-Duplex Communication: Events and callbacks are natively supported.&lt;/li&gt;
&lt;li&gt;Encryption: Secure communication with AES/RSA-based encryption.&lt;/li&gt;
&lt;li&gt;Authorization: Token-based authentication ensures only authorized clients can connect.&lt;/li&gt;
&lt;li&gt;High Performance: Optimize IPC for the local machine using memory-mapped files.&lt;/li&gt;
&lt;li&gt;Easy Error Handling: Use WitComExceptionFault to handle communication errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;WitCom is a robust and modern alternative for inter-process communication in .NET, combining the best features of WCF with modern transport options. For more information, visit &lt;a href="https://ratner.io/witcom/" rel="noopener noreferrer"&gt;WitCom’s documentation&lt;/a&gt; and explore examples on &lt;a href="https://github.com/dmitrat/WitCom" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>programming</category>
      <category>backenddevelopment</category>
      <category>remote</category>
    </item>
    <item>
      <title>WitCom: Modernizing Client-Server Communication</title>
      <dc:creator>Dmitry</dc:creator>
      <pubDate>Mon, 06 Jan 2025 10:45:42 +0000</pubDate>
      <link>https://dev.to/dmitrat/witcom-modernizing-client-server-communication-28an</link>
      <guid>https://dev.to/dmitrat/witcom-modernizing-client-server-communication-28an</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/dmitrat/WitCom/tree/main" rel="noopener noreferrer"&gt;WitCom&lt;/a&gt; is a versatile and innovative API designed to simplify client-server communication, offering intuitive interfaces, robust security, and flexible serialization options. With support for multiple transport mechanisms, including WebSocket, TCP, REST, and even Memory-mapped files, it caters to diverse application needs. Its event-driven architecture and customizable components make it an ideal choice for small-scale projects or complex distributed systems where both client and server are implemented with .Net, positioning WitCom as a modern and simple-to-use alternative to WCF and SignalR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features of WitCom
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplicity and Native Use&lt;/strong&gt;: WitCom’s design ensures intuitive implementation. By eliminating the reliance on text-based messaging, lambda functions, or complex expressions, it simplifies the development process, especially for developers transitioning from other frameworks. Its native approach means developers work with familiar tools and paradigms, reducing the learning curve.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Duplex Communication&lt;/strong&gt;: WitCom excels in enabling full duplex communication, allowing seamless two-way message exchanges between client and server. Built-in event and callback support accommodates a wide array of delegate types, such as PropertyChangedEventHandler. This duplex model is ideal for applications requiring constant interaction, like live updates, synchronized data sharing, or collaborative systems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Client-Side Proxy Mirrors Server&lt;/strong&gt;: A defining feature of WitCom is its ability to create a dynamic proxy on the client side that mirrors the interface of the server object. This means that by simply invoking methods or accessing properties on the client’s proxy, you directly interact with the server. Additionally, subscribing to events on the proxy seamlessly triggers server-side events, making the entire client-server communication invisible and effortless for the user. Developers work naturally with the interface, while WitCom handles all underlying communication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Interface-Driven Architecture&lt;/strong&gt;: Service interfaces in WitCom are defined using standard .NET interfaces. This promotes strong type safety and allows for the auto-generation of dynamic client-side proxies that act as exact replicas of server-side services, ensuring consistent behavior across the application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Transport Versatility&lt;/strong&gt;: WitCom supports a variety of transport mechanisms, making it adaptable to a range of scenarios and infrastructures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory-Mapped Files&lt;/strong&gt;: Designed for ultra-fast inter-process communication (IPC) on a single machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Named Pipes&lt;/strong&gt;: Effective for IPC within the same network or machine, supporting multiple clients.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TCP&lt;/strong&gt;: Provides robust and reliable communication for distributed systems, making it suitable for large-scale applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebSocket&lt;/strong&gt;: Enables efficient, real-time bidirectional communication across web platforms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;REST&lt;/strong&gt;: Simplifies interaction with non-.NET clients, providing rapid deployment of RESTful APIs for external integrations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Extensive Customization&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full support for generic functions and properties.&lt;/li&gt;
&lt;li&gt;Flexible serialization formats, including JSON and MessagePack.&lt;/li&gt;
&lt;li&gt;Optional security features, such as end-to-end encryption and token-based authorization.&lt;/li&gt;
&lt;li&gt;Developers can override default implementations for highly specific requirements, ensuring the API adapts to unique project demands.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Enhanced Security: Encryption and Authorization
&lt;/h2&gt;

&lt;p&gt;Security lies at the heart of WitCom’s design, providing robust mechanisms for both encryption and authorization. These capabilities are built on flexible, extensible interfaces, with default implementations included for most standard use cases.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;End-to-End Encryption&lt;/strong&gt;: WitCom’s encryption framework ensures secure communication between clients and servers. By default, AES (Advanced Encryption Standard) handles symmetric encryption, while RSA facilitates secure key exchange. This layered security provides:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Confidentiality&lt;/strong&gt;: Ensures that transmitted data is encrypted and inaccessible to unauthorized entities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrity&lt;/strong&gt;: Validates the integrity of the data, preventing tampering during transit.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Developers can implement custom encryption logic by adhering to &lt;code&gt;IEncryptorServer&lt;/code&gt;and &lt;code&gt;IEncryptorClient&lt;/code&gt; interfaces, allowing tailored security measures where required.&lt;/p&gt;

&lt;p&gt;Example configuration for enabling encryption:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var server = WitComServerBuilder.Build(options =&amp;gt;
{
    options.WithEncryption();
});

var client = WitComClientBuilder.Build(options =&amp;gt;
{
    options.WithEncryption();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Token-Based Authorization&lt;/strong&gt;: Authorization is seamlessly integrated through token-based systems, providing an additional layer of security. By default, WitCom includes static token validators suitable for most scenarios. Developers can extend functionality by implementing &lt;code&gt;IAccessTokenValidator&lt;/code&gt;for customized authorization logic, allowing for integration with advanced identity management systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class AccessTokenValidator : IAccessTokenValidator
{
    private readonly string _validToken;

    public AccessTokenValidator(string validToken)
    {
        _validToken = validToken;
    }

    public bool IsAuthorizationTokenValid(string token)
    {
        return token == _validToken;
    }
}

var server = WitComServerBuilder.Build(options =&amp;gt;
{
    options.WithAccessTokenValidator(new AccessTokenValidator("secure-token"));
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Serialization Options: JSON and MessagePack
&lt;/h2&gt;

&lt;p&gt;Serialization in WitCom is both flexible and efficient, catering to a variety of application needs. Default implementations of serializers are provided, but developers are free to customize by implementing the &lt;code&gt;IMessageSerializer&lt;/code&gt;interface.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JSON Serialization&lt;/strong&gt;: JSON is the default format, offering unparalleled readability and widespread support across platforms. Its human-readable format is particularly advantageous during debugging and integration with third-party systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var server = WitComServerBuilder.Build(options =&amp;gt;
{
    options.WithJson();
});

var client = WitComClientBuilder.Build(options =&amp;gt;
{
    options.WithJson();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MessagePack Serialization&lt;/strong&gt;: For high-performance applications, MessagePack offers a compact binary serialization format that significantly reduces payload size. This is ideal for bandwidth-sensitive environments or systems with stringent performance requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var server = WitComServerBuilder.Build(options =&amp;gt;
{
    options.WithMessagePack();
});

var client = WitComClientBuilder.Build(options =&amp;gt;
{
    options.WithMessagePack();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting Up WitCom
&lt;/h2&gt;

&lt;p&gt;To illustrate the simplicity of WitCom, consider the following example for setting up a basic service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Define the Service Interface&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface IExampleService
{
    event ExampleServiceEventHandler ProcessingStarted;
    event ExampleServiceProgressEventHandler ProgressChanged;
    event ExampleServiceProcessingEventHandler ProcessingCompleted;

    bool StartProcessing();
    void StopProcessing();
}

public delegate void ExampleServiceEventHandler();
public delegate void ExampleServiceProgressEventHandler(double progress);
public delegate void ExampleServiceProcessingEventHandler(ProcessingStatus status);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Implement the Service&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ExampleService : IExampleService
{
    public event ExampleServiceEventHandler ProcessingStarted = delegate { };
    public event ExampleServiceProgressEventHandler ProgressChanged = delegate { };
    public event ExampleServiceProcessingEventHandler ProcessingCompleted = delegate { };

    private CancellationTokenSource? _cancellationTokenSource;

    public bool StartProcessing()
    {
        if (_cancellationTokenSource != null) return false;
        _cancellationTokenSource = new CancellationTokenSource();
        Task.Run(Process);
        ProcessingStarted();
        return true;
    }

    public void StopProcessing()
    {
        _cancellationTokenSource?.Cancel();
    }

    private void Process()
    {
        for (int i = 1; i &amp;lt;= 100; i++)
        {
            if (_cancellationTokenSource?.IsCancellationRequested == true)
            {
                ProcessingCompleted(ProcessingStatus.Interrupted);
                return;
            }
            ProgressChanged(i);
            Thread.Sleep(100);
        }
        ProcessingCompleted(ProcessingStatus.Success);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Configure the Server&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var server = WitComServerBuilder.Build(options =&amp;gt;
{
    options.WithService(new ExampleService());
    options.WithWebSocket("http://localhost:5000", 10);
    options.WithJson();
    options.WithEncryption();
});

server.StartWaitingForConnection();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;Connect the Client&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var client = WitComClientBuilder.Build(options =&amp;gt;
{
    options.WithWebSocket("ws://localhost:5000");
    options.WithJson();
    options.WithEncryption();
});

await client.ConnectAsync(TimeSpan.FromSeconds(5), CancellationToken.None);
var service = client.GetService&amp;lt;IExampleService&amp;gt;();

service.ProcessingStarted += () =&amp;gt; Console.WriteLine("Processing Started");
service.ProgressChanged += progress =&amp;gt; Console.WriteLine($"Progress: {progress}%");
service.ProcessingCompleted += status =&amp;gt; Console.WriteLine($"Processing Completed: {status}");

service.StartProcessing();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Examples and GitHub Repository
&lt;/h2&gt;

&lt;p&gt;Explore the complete source code and examples for WitCom:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Repository: &lt;a href="https://github.com/dmitrat/WitCom/tree/main" rel="noopener noreferrer"&gt;WitCom&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Inter-Process Communication Examples: &lt;a href="https://github.com/dmitrat/WitCom/tree/main/Examples/InterProcess" rel="noopener noreferrer"&gt;Examples/InterProcess&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Multi-Client Service Examples: &lt;a href="https://github.com/dmitrat/WitCom/tree/main/Examples/Services" rel="noopener noreferrer"&gt;Examples/Services&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  WitCom Advantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ease of Use&lt;/strong&gt;: WitCom eliminates boilerplate code, offering an intuitive setup experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event-Driven Model&lt;/strong&gt;: Its event-centric design makes it ideal for reactive and real-time applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Features like memory-mapped files optimize performance for local IPC scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: Extensive transport and serialization options cater to diverse use cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WitCom empowers developers with a robust yet simple framework for modern client-server communication. By combining powerful features, high performance, and flexibility, it meets the demands of both small-scale and enterprise-level systems. Whether building responsive applications or managing large-scale distributed systems, WitCom represents a significant step forward in .NET communication frameworks.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>programming</category>
      <category>backenddevelopment</category>
      <category>remote</category>
    </item>
    <item>
      <title>Streamlining .NET Development with Practical Aspects</title>
      <dc:creator>Dmitry</dc:creator>
      <pubDate>Wed, 20 Nov 2024 14:51:27 +0000</pubDate>
      <link>https://dev.to/dmitrat/streamlining-net-development-with-practical-aspects-153b</link>
      <guid>https://dev.to/dmitrat/streamlining-net-development-with-practical-aspects-153b</guid>
      <description>&lt;p&gt;Aspect-oriented programming (AOP) provides a robust approach to encapsulate cross-cutting concerns into reusable components called aspects. By separating these concerns from business logic, AOP helps streamline development, reduce boilerplate code, and enhance maintainability. In this article, I’ll explore three practical aspects that I am using for almost all my projects: Notify, Log, and Bindable, demonstrating how they simplify common programming tasks and improve code quality.&lt;/p&gt;

&lt;p&gt;All examples are implemented using the &lt;a href="https://github.com/pamidur/aspect-injector" rel="noopener noreferrer"&gt;Aspect Injector&lt;/a&gt;, but the same logic can be adapted to other AOP frameworks. This approach is not tied to any specific library and can be easily customized to fit your project’s needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating Property Change Notifications with the Notify Aspect
&lt;/h2&gt;

&lt;p&gt;When working with the MVVM pattern (and not only), there’s a frequent need to track changes in properties.&lt;br&gt;
To achieve this, the model class for which we want to track property changes must implement the &lt;code&gt;INotifyPropertyChanged&lt;/code&gt; interface. Each property then has to explicitly invoke the &lt;code&gt;PropertyChangedEventHandler&lt;/code&gt; when modified:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotifyPropertyChanged&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;PropertyChangedEventHandler&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;PropertyChanged&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;delegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;m_text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;get&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m_text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;set&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;m_text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nf"&gt;PropertyChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PropertyChangedEventArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach bloats the code and requires inserting repetitive constructs. Even when simplified, such as avoiding plain text arguments, it still results in verbose code, increasing the chance of missing something or introducing errors.&lt;/p&gt;

&lt;p&gt;This problem is perfectly solved using aspects. Fortunately, the Aspect Injector framework provides a built-in &lt;code&gt;Notify&lt;/code&gt; aspect for automating property change notifications. With this, the above code can be rewritten as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Notify&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The aspect will automatically generate a &lt;code&gt;PropertyChangedEventHandler&lt;/code&gt; and invoke it on behalf of the class. This works seamlessly with WPF UI.&lt;/p&gt;

&lt;p&gt;But what if we want to monitor property changes for custom purposes? For example, we might need to attach to the &lt;code&gt;PropertyChanged&lt;/code&gt; event and execute additional logic when properties change. Unfortunately, relying solely on the Notify aspect provided by Aspect Injector won’t work as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotifyPropertyChanged&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;PropertyChangedEventHandler&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;PropertyChanged&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;delegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PropertyChanged&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnPropertyChanged&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnPropertyChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PropertyChangedEventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PropertyName&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// This block will never be executed...&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Notify&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To enable this, we need to modify the implementation of the aspect. Specifically, the aspect should detect whether the class implements &lt;code&gt;INotifyPropertyChanged&lt;/code&gt; and invoke the internal event. This can be achieved using the power of reflection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;FirePropertyChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;propertyName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;INotifyPropertyChanged&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;eventDelegate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetPropertyChangedField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;())?.&lt;/span&gt;&lt;span class="nf"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;MulticastDelegate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventDelegate&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;delegates&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventDelegate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetInvocationList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dlg&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;delegates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;dlg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dlg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PropertyChangedEventArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;propertyName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TargetInvocationException&lt;/span&gt; &lt;span class="n"&gt;targetInvocationException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetInvocationException&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InnerException&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;targetInvocationException&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InnerException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;FieldInfo&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;GetPropertyChangedField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="n"&gt;objType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;property&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFields&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Instance&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NonPublic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SingleOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FieldType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PropertyChangedEventHandler&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;objType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseType&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;GetInterface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;INotifyPropertyChanged&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;objType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A detailed implementation of this aspect can be found in the &lt;a href="https://github.com/dmitrat/OutWit/tree/main/Sources/Common/OutWit.Common.Aspects" rel="noopener noreferrer"&gt;OutWit repository on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use this extended functionality, you need to install the &lt;code&gt;OutWit.Common.Aspects&lt;/code&gt; NuGet package and utilize the &lt;code&gt;Notify&lt;/code&gt; aspect from it. With this modification, the code will behave as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotifyPropertyChanged&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;PropertyChangedEventHandler&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;PropertyChanged&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;delegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PropertyChanged&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;OnPropertyChanged&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnPropertyChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PropertyChangedEventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PropertyName&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I am here!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Notify&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This extended &lt;code&gt;Notify&lt;/code&gt; aspect ensures both WPF compatibility and the ability to react to property changes for custom purposes, making it a robust solution for property change tracking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streamlining Logging with the Log Aspect
&lt;/h2&gt;

&lt;p&gt;Maintaining logs is an essential practice for any sufficiently complex application, as it greatly simplifies debugging and support. Logs help developers understand the sequence of events or user actions that led to a specific result.&lt;/p&gt;

&lt;p&gt;For larger projects, explicitly calling logging methods every time they’re needed can be tedious and error-prone. The &lt;code&gt;OutWit.Common.Logging&lt;/code&gt; package provides a powerful set of logging aspects that can automate much of this process.&lt;br&gt;
The source code for these aspects is available &lt;a href="https://github.com/dmitrat/OutWit/tree/main/Sources/Common/OutWit.Common.Logging" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This implementation is based on Serilog but can be easily adapted to other logging frameworks. Before using these aspects, you must initialize the logger:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LoggerConfiguration&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinimumLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LogEventLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Information&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enrich&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithExceptionDetails&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteTo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"D:\Log\Log.txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;rollingInterval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RollingInterval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;rollOnFileSizeLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;fileSizeLimitBytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;524288&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateLogger&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once initialized, the following three aspects become available:&lt;/p&gt;

&lt;h3&gt;
  
  
  Log Aspect
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Log&lt;/code&gt; aspect can be applied to individual methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoSomething1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoSomething2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or to an entire class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoSomething1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoSomething2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When applied to a class, the Log aspect is effectively applied to all methods within the class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does this aspect do?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Exception Handling:&lt;/strong&gt;&lt;br&gt;
The Log aspect wraps method execution in a &lt;code&gt;try-catch&lt;/code&gt; block. If an exception is thrown, it logs the exception details, including its parameters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Method Execution Logging:&lt;/strong&gt;&lt;br&gt;
If the logger’s &lt;code&gt;MinimumLevel&lt;/code&gt; is set to &lt;code&gt;Information&lt;/code&gt; or lower, the aspect logs each method call (excluding property getters and setters).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Detailed Property Access Logging:&lt;/strong&gt;&lt;br&gt;
When the logger’s &lt;code&gt;MinimumLevel&lt;/code&gt; is set to &lt;code&gt;Verbose&lt;/code&gt;, the aspect also logs access to properties.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This allows you to control the level of detail in your logs by simply adjusting the logger’s configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  NoLog Aspect
&lt;/h3&gt;

&lt;p&gt;If the &lt;code&gt;Log&lt;/code&gt; aspect is applied to an entire class, but you need to exclude specific methods from logging (e.g., frequently called methods that could clutter the logs), the &lt;code&gt;NoLog&lt;/code&gt; aspect can be used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoSomething1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NoLog&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoSomething2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;NoLog&lt;/code&gt; aspect disables logging for the specified method, even if the &lt;code&gt;Log&lt;/code&gt; aspect is applied at the class level.&lt;/p&gt;

&lt;h3&gt;
  
  
  Measure Aspect
&lt;/h3&gt;

&lt;p&gt;Sometimes, the primary goal is to measure how long an operation takes to execute. Applying the &lt;code&gt;Measure&lt;/code&gt; aspect to a method will log its execution time in milliseconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoSomething1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Measure&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;DoSomething2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;DoSomething2&lt;/code&gt; is called, the log will include a message indicating how long the method took to execute.&lt;/p&gt;

&lt;p&gt;These aspects not only simplify logging but also ensure consistency across your application. Whether you need basic logging, selective exclusions, or precise performance measurements, these tools provide a flexible and powerful solution for your .NET applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplifying DependencyProperty Management with the Bindable Aspect
&lt;/h2&gt;

&lt;p&gt;When working with WPF, dealing with &lt;code&gt;DependencyProperty&lt;/code&gt; is a frequent and often tedious task. Declaring a &lt;code&gt;DependencyProperty&lt;/code&gt; correctly is even more cumbersome than handling &lt;code&gt;INotifyPropertyChanged&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For every &lt;code&gt;DependencyProperty&lt;/code&gt;, you typically need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Declare the static DependencyProperty:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;DependencyProperty&lt;/span&gt; &lt;span class="n"&gt;ValueProperty&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
&lt;span class="n"&gt;DependencyProperty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyControl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PropertyMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PropertyChangedCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OnValueChanged&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create a local property to access the value:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ValueProperty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ValueProperty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This process is verbose and error-prone, with multiple places where mistakes can be introduced or something might be forgotten.&lt;/p&gt;

&lt;p&gt;To simplify this workflow, the &lt;code&gt;OutWit.Common.MVVM&lt;/code&gt; package provides a set of tools, including the Bindable aspect. The source code is available &lt;a href="https://github.com/dmitrat/OutWit/tree/main/Sources/Common/OutWit.Common.MVVM" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making DependencyProperty Registration Cleaner
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;BindingUtils&lt;/code&gt; utility included in the package simplifies the declaration of &lt;code&gt;DependencyProperty&lt;/code&gt; by offering a more concise syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;DependencyProperty&lt;/span&gt; &lt;span class="n"&gt;ValueProperty&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
&lt;span class="n"&gt;BindingUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyControl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;OnValueChanged&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the &lt;code&gt;DependencyProperty&lt;/code&gt; registration cleaner and less error-prone, improving code readability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Eliminating GetValue and SetValue with Bindable Aspect
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Bindable&lt;/code&gt; aspect takes simplification even further by eliminating the need for explicit &lt;code&gt;GetValue&lt;/code&gt; and &lt;code&gt;SetValue&lt;/code&gt; calls in your property definition. Here’s how it looks in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Bindable&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the &lt;code&gt;Bindable&lt;/code&gt; aspect, the boilerplate code is reduced, resulting in cleaner and more maintainable classes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Default Behavior and Custom Names
&lt;/h3&gt;

&lt;p&gt;By default, the aspect assumes that the &lt;code&gt;DependencyProperty&lt;/code&gt; corresponding to a property named &lt;code&gt;[Name]&lt;/code&gt; is declared as &lt;code&gt;[Name]Property&lt;/code&gt;. For example, for the property &lt;code&gt;Value&lt;/code&gt;, the aspect expects the &lt;code&gt;DependencyProperty&lt;/code&gt; to be named &lt;code&gt;ValueProperty&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If your &lt;code&gt;DependencyProperty&lt;/code&gt; uses a different name, you can specify it explicitly as a parameter to the attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Bindable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CustomDependencyProperty"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows flexibility while still maintaining a concise and readable property definition.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Bindable&lt;/code&gt; aspect, combined with &lt;code&gt;BindingUtils&lt;/code&gt;, significantly reduces the amount of repetitive code required when working with &lt;code&gt;DependencyProperty&lt;/code&gt;. It ensures consistency and improves readability, helping developers focus more on the logic of their application rather than boilerplate code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Aspects are a powerful tool to simplify repetitive and error-prone coding tasks, allowing developers to focus on the core logic of their applications. Here, I explored three practical aspects—&lt;code&gt;Notify&lt;/code&gt;, &lt;code&gt;Log&lt;/code&gt;, and &lt;code&gt;Bindable&lt;/code&gt;—and demonstrated how they can streamline property change notifications, logging, and &lt;code&gt;DependencyProperty&lt;/code&gt; management in .NET development.&lt;/p&gt;

&lt;p&gt;All examples presented here leverage the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;OutWit.Common.Aspects&lt;/code&gt;&lt;/strong&gt;: &lt;a href="https://github.com/dmitrat/OutWit/tree/main/Sources/Common/OutWit.Common.Aspects" rel="noopener noreferrer"&gt;Source Code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;OutWit.Common.Logging&lt;/code&gt;&lt;/strong&gt;: &lt;a href="https://github.com/dmitrat/OutWit/tree/main/Sources/Common/OutWit.Common.Logging" rel="noopener noreferrer"&gt;Source Code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;OutWit.Common.MVVM&lt;/code&gt;&lt;/strong&gt;: &lt;a href="https://github.com/dmitrat/OutWit/tree/main/Sources/Common/OutWit.Common.MVVM" rel="noopener noreferrer"&gt;Source Code&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By incorporating these tools into your projects, you can reduce boilerplate code, improve maintainability, and make your codebase cleaner and more efficient.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>wpf</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
