Blogs @ UGIdotNEThttp://blogs.ugidotnet.org/MainFeed.aspxBloggers UGIdotNETSubtext Version 2.6.0.0Dapr - Resiliencyhttp://blogs.ugidotnet.org/martinobordin/archive/2024/02/05/dapr-resiliency.aspxMon, 05 Feb 2024 09:27:24 GMThttp://blogs.ugidotnet.org/martinobordin/archive/2024/02/05/dapr-resiliency.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/102641.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/commentRss/102641.aspxhttp://blogs.ugidotnet.org/martinobordin/archive/2024/02/05/dapr-resiliency.aspx#comment0http://blogs.ugidotnet.org/martinobordin/services/trackbacks/102641.aspxDapr - Resiliency<p>As we know, in a distributed system we have to take into account more complexity and deal with its <a href="https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing">fallacies</a>. Since several moving parts could potentially be broken or be unreachable, we must design upfront our application with resiliency in mind, to minimize the impact of bad events and continue operating.</p> <p>Dapr gives us out-of-the-box features that allow our applications to handle temporary failures.</p> <p>All we have to do is to create a YAML file where we define <a href="https://docs.dapr.io/operations/resiliency/policies/">policies</a> and <a href="https://docs.dapr.io/operations/resiliency/targets/">targets</a>.</p> <p>Policies are how we want to handle errors:</p> <ul> <li><strong>Timeout</strong>,  to terminate operations after defined intervals </li> <li><strong>Circuit breaking</strong>, to 'open' the circuit when there are several errors in order not to flood the system and give it time to restart the failing service </li> <li><strong>Retry</strong>, to retry failed operations</li> </ul> <p>Targets are where we want to apply such policies:</p> <ul> <li><strong>Apps</strong>, our services (defined in docker-compose in our sample) </li> <li><strong>Components</strong>, the different building blocks of Dapr </li> <li><strong>Actors</strong>, the actor operations (not used in our sample)</li> </ul> <p>I won't post the full YAML specification in this article, but I prepared a full example with comments in the GitHub repository.</p> <p>Check it out <a href="https://github.com/martinobordin/MicroDelivery/blob/master/dapr/components/resiliency.yaml">here</a>.</p> <p>Once done, we configure the Dapr sidecar to load the resiliency configuration using the <a href="invalid://">-resources-path</a> argument.</p> <p><img src="https://media.licdn.com/dms/image/D4D12AQENJxKq_SjBqQ/article-cover_image-shrink_600_2000/0/1687848229433?e=1712793600&amp;v=beta&amp;t=BKa0nbOe8efIy7f3Y4kUxCoJAeRdSnXzbDti06sRoGQ" width="656" height="172" /></p> <p>In the next article, we'll see observability in Dapr</p><img src="http://blogs.ugidotnet.org/martinobordin/aggbug/102641.aspx" width="1" height="1" />Martino BordinDapr - Secret managementhttp://blogs.ugidotnet.org/martinobordin/archive/2024/01/12/dapr-secret-management.aspxFri, 12 Jan 2024 14:29:02 GMThttp://blogs.ugidotnet.org/martinobordin/archive/2024/01/12/dapr-secret-management.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/102640.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/commentRss/102640.aspxhttp://blogs.ugidotnet.org/martinobordin/archive/2024/01/12/dapr-secret-management.aspx#comment0http://blogs.ugidotnet.org/martinobordin/services/trackbacks/102640.aspxDapr - Secret management<p>Dapr Secrets management is a feature that provides a secure and scalable way to manage application secrets, such as API keys, passwords, and tokens. You can use different cloud providers and environments such as Azure Key Vault, AWS Secrets Manager, HashiCorp Vault, or Kubernetes Secrets.</p> <p>In our example, we'll use a JSON file (not recommended in production!) to store the following secrets:</p> <blockquote> <pre><font color="#000000">"httpbindingtoken": "my auth token",   "ConnectionStrings": {     "SqlServer": "Server=sqlserver;Database=CustomersDb;User Id=sa;Password=admin12345!;TrustServerCertificate=true",     "PostgreSQL": "Server=postgres;Port=5432;Database=ProductsDb;User Id=admin;Password=admin12345;",     "MongoDb": "mongodb://mongo:27017"   },   "MongoDb": {     "DatabaseName": "OrderDb",     "OrdersCollectionName": "Orders"   } }</font></pre> </blockquote> <pre><font color="#000000"><br /></font></pre> <p>We have two way to retrieve them:</p> <ul> <li><strong>declaratively</strong>, in the components spec files </li> <li><strong>programmatically</strong>, using the Dapr APIs</li> </ul> <p>We had a glimpse of the first approach in the previous article, where we configured the Http Output Binding component.</p> <p>Quick recall:</p> <blockquote> <pre><font color="#000000">apiVersion: dapr.io/v1alph kind: Component metadata: name: httpbinding spec: type: bindings.http version: v1 metadata: - name: url value: http://echorestbot.azurewebsites.net/microdelivery - name: securityToken secretKeyRef: name: httpbindingtoken key: httpbindingtoken - name: securityTokenHeader value: "Authorization" auth: secretStore: localsecretstore</font></pre> </blockquote> <p>Here we are configuring some metadata and you may notice that for the item <strong>securityToken </strong>instead of directly inserting the value, we are declaring that we want to use the key <strong>httpbindingtoken </strong>retrieve in <strong>localsecretstore</strong><em>.</em></p> <p><strong>Localsecretstore </strong>is the name of the component for secret management, configured as usual in the YAML file</p> <blockquote> <pre><font color="#000000">apiVersion: dapr.io/v1alpha kind: Component metadata:   name: localsecretstore spec:   type: secretstores.local.file   version: v1   metadata:   - name: secretsFile     value: components/secrets.json   - name: nestedSeparator     value: ":"</font></pre> </blockquote> <p>Here we are basically declaring where we store the secrets (in the file <strong>secrets.json</strong>) and what is the separator character for nested configuration (colon is the default).</p> <p>To use it programmatically, we have to add the Nuget package <strong>Dapr.Extensions.Configuration</strong> in our project and register it with the following lines of code</p> <blockquote> <pre><font color="#000000">var builder = WebApplication.CreateBuilder(args) builder.Configuration.AddDaprSecretStore( "localsecretstore", new DaprClientBuilder().Build(), new[] { ":" });</font></pre> </blockquote> <pre><br /></pre> <pre>Once done, we can access our secret simply using the standard <em>IConfiguration.</em></pre> <pre><em><br /></em></pre> <blockquote> <pre><font color="#000000">public OrdersRepository(IConfiguration configuration { var clientSettings = MongoClientSettings .FromConnectionString(configuration .GetConnectionString("MongoDb"));    var client = new MongoClient(clientSettings);    var database = client .GetDatabase(configuration .GetValue&lt;string&gt;("MongoDb:DatabaseName")); this.orders = database.GetCollection&lt;Order&gt;(configuration .GetValue&lt;string&gt;("MongoDb:OrdersCollectionName")); })</font></pre> </blockquote> <pre><br /></pre> <p>That's it!</p> <p>In the next article, we'll see how to leverage the resiliency feature of Dapr.</p><img src="http://blogs.ugidotnet.org/martinobordin/aggbug/102640.aspx" width="1" height="1" />Martino BordinDapr - Pub/sub &amp; Output Bindinghttp://blogs.ugidotnet.org/martinobordin/archive/2023/12/06/dapr-pubsub-amp-output-binding.aspxWed, 06 Dec 2023 15:53:18 GMThttp://blogs.ugidotnet.org/martinobordin/archive/2023/12/06/dapr-pubsub-amp-output-binding.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/102639.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/commentRss/102639.aspxhttp://blogs.ugidotnet.org/martinobordin/archive/2023/12/06/dapr-pubsub-amp-output-binding.aspx#comment0http://blogs.ugidotnet.org/martinobordin/services/trackbacks/102639.aspxDapr - Pub/sub &amp; Output Binding<p>In the last article, once created an order we published a message, called <strong>OrderSubmittedIntegrationEvent </strong>with all the relevant information.</p> <p>How can we subscribe to this event in other services?</p> <p>In Dapr there are two ways:</p> <ul> <li><strong>declaratively</strong>, where subscriptions are defined in an external file </li> <li><strong>programmatically</strong>, where subscriptions are defined in our code</li> </ul> <p>We're going to use the second method in the <strong>Notifications </strong>and <strong>Shipping</strong> microservices along with the <strong>Output binding </strong>building block</p> <p>What is an Output binding? It's a way to invoke external resources just by passing a payload and additional metadata.</p> <p>Let's see them in action!</p> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQFZv34VwWq4zA/article-inline_image-shrink_1500_2232/0/1681579684758?e=1707350400&amp;v=beta&amp;t=uoWlwsHnPogtNnIMSWtxQBaphTKWn6zzzLACs5XCT28" /></p> <p>Notifications microservice</p> <p>The notification microservice will have just one method that is going to use the <a href="https://docs.dapr.io/reference/components-reference/supported-bindings/smtp/">SMTP output binding</a> to send an email to inform the customer that the order has been confirmed and what discount has been applied.</p> <p>Here is the stripped version of the code, check <a href="https://github.com/martinobordin/MicroDelivery/blob/master/src/MicroDelivery.Notifications.Api/Controllers/NotificationsController.cs">GitHub</a> for the complete one.</p> <blockquote> <pre><font color="#000000">[HttpPost [Topic("rabbitmqpubsub", "OrderSubmittedEventTopic")] public async Task&lt;ActionResult&gt; OnOrderSubmittedEventAsync( OrderSubmittedIntegrationEvent orderSubmittedIntegrationEvent) { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"Hello {orderSubmittedIntegrationEvent.CustomerFirstName} {orderSubmittedIntegrationEvent.CustomerLastName}&lt;br&gt;"); stringBuilder.AppendLine($"Your order &lt;strong&gt;#{orderSubmittedIntegrationEvent.OrderId.ToString()[..6]}&lt;/strong&gt; has been shipped.&lt;br&gt;&lt;br&gt;"); stringBuilder.AppendLine($"Your CRAZY DISCOUNT is &lt;strong&gt;#{orderSubmittedIntegrationEvent.TotalDiscount}%&lt;/strong&gt;!&lt;br&gt;&lt;br&gt;"); var message = stringBuilder.ToString(); var metadata = new Dictionary&lt;string, string&gt; { { "emailTo", orderSubmittedIntegrationEvent.CustomerEmail }, { "subject", $"Order Shipped!" }, { "priority", "1" } }; await this.daprClient .InvokeBindingAsync( "smtpbinding", "create", message, metadata); return Ok(); }]</font></pre> </blockquote> <p>The first thing you can notice is that we're using the <strong>Topic</strong> attribute to subscribe to the topic <strong>OrderSubmittedEventTopic </strong>on the <strong>rabbitmqpubsub </strong>component.</p> <p>Dapr is going to invoke this method once a new message is published to that topic, and we receive the payload as a parameter (<strong>OrderSubmittedIntegrationEvent</strong>). We then use the payload to create an email and send it using the <strong>InvokeBindingAsync</strong>, passing as a parameter the name of the binding component (<strong>smtpbinding</strong>), the body of the email, and some metadata (subject, mail address, priority).</p> <p>Of course, we have to configure the binding in the YAML specification:</p> <pre>apiVersion: dapr.io/v1alpha kind: Component metadata:   name: smtpbinding spec:   type: bindings.smtp   version: v1   metadata:   - name: host     value: "smtp4dev"   - name: port     value: "25"   - name: emailFrom     value: "no-reply@microdelivery.com"</pre> <p>For testing purposes, I'm using an email server called <a href="https://github.com/rnwood/smtp4dev">smtp4dev</a> hosted in docker to send and check emails.</p> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQH8TybGkQ3gdA/article-inline_image-shrink_1500_2232/0/1681581762546?e=1707350400&amp;v=beta&amp;t=gm03f2c5e-E8L_PBL0Bar1iJFVGcp4q9p_opnOvMJ6Y" /></p> <p>The smtp4dev User Interface</p> <p>Now let's see the shippings service.</p> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQGNAIabPnjIpQ/article-inline_image-shrink_1500_2232/0/1681582440338?e=1707350400&amp;v=beta&amp;t=nqWrW5AHXLa2heNpnP4MbXQ0ixuyh5mBUxNJ-4sMnkE" /></p> <p>Shipping microservice</p> <p>All the logic is in the method <strong>OnOrderSubmittedEvent</strong>, where we're subscribing to the topic <strong>OrderSubmittedEventTopic, </strong>and we're performing an HTTP request using the <a href="https://docs.dapr.io/reference/components-reference/supported-bindings/http/">HTTP Output Binding</a> (to simulate a call to an external supplier). Once done, we publish the <strong>OrderShippedIntegrationEvent </strong>that will be handled by the <strong>Orders </strong>microservice to mark the order as shipped.</p> <blockquote> <pre><font color="#000000">[HttpPost [Topic("rabbitmqpubsub", "OrderSubmittedEventTopic")] public async Task&lt;ActionResult&gt; OnOrderSubmittedEvent( OrderSubmittedIntegrationEvent orderSubmittedIntegrationEvent) { await this.daprClient.InvokeBindingAsync( "httpbinding", "post", orderSubmittedIntegrationEvent); var orderShippedIntegrationEvent = new OrderShippedIntegrationEvent() { OrderId = orderSubmittedIntegrationEvent.OrderId, ShippedAtUtc = DateTime.UtcNow }; await daprClient.PublishEventAsync( "rabbitmqpubsub", "OrderShippedEventTopic", orderShippedIntegrationEvent); return Ok(); }]</font></pre> </blockquote> <p>As in the notifications microservice, we use the <strong>InvokeBindingAsync</strong>, this time to call the HTTP endpoint, passing the <strong>orderSubmittedIntegrationEvent </strong>as payload.</p> <p>The binding is configured with the following YAML specification:</p> <blockquote> <pre><font color="#000000">apiVersion: dapr.io/v1alpha kind: Component metadata: name: httpbinding spec: type: bindings.http version: v1 metadata: - name: url value: http://echorestbot.azurewebsites.net/microdelivery - name: securityToken secretKeyRef: name: httpbindingtoken key: httpbindingtoken - name: securityTokenHeader value: "Authorization" auth: secretStore: localsecretstore</font></pre> </blockquote> <p>Here you see that we want to perform a POST request to the URL <a href="http://echorestbot.azurewebsites.net/microdelivery">http://echorestbot.azurewebsites.net/microdelivery</a> (it's a <a href="https://github.com/martinobordin/EchoREST">simple API</a> I built that gives you back the request details). We are also passing a token in the "Authorization" header; the value of the token is read by using the secret management build block (more info in the next article).</p> <p>Here is an example of the request we made to the EchoRest endpoint, where you can see the payload containing the order's detail:</p> <blockquote> <pre><font color="#000000">{   "RequestIdentifier": "14085696-218e-42f2-8966-7a0b37b506ea",   "Date": "2023-05-01T20:02:07.2657896Z",   "Url": "http://echorestbot.azurewebsites.net/microdelivery",   "Body": "{\"orderId\":\"307998cc-53c9-46cf-9dca-06df25419496\",\"customerId\":1,\"customerFirstName\":\"Joe\",\"customerLastName\":\"Doe\",\"customerEmail\":\"joe.doe@email.com\",\"orderLineItems\":[{\"productId\":1,\"productName\":\"Tomato salad\",\"quantity\":3,\"price\":8,\"discountedPrice\":8},{\"productId\":2,\"productName\":\"Margherita\",\"quantity\":3,\"price\":6,\"discountedPrice\":6}],\"totalDiscount\":0,\"eventId\":\"823132ef-197a-4fc3-8da4-175966bae8dc\"}",   "Headers": [     {       "Key": "Accept",       "Value": "application/json; charset=utf-8"     },     {       "Key": "Host",       "Value": "echorestbot.azurewebsites.net"     },        {       "Key": "Authorization",       "Value": "my auth token"     },     {       "Key": "Content-Type",       "Value": "application/json; charset=utf-8"     },     {       "Key": "Content-Length",       "Value": "412"     }          ],   "Method": "POST",   "Path": {     "Value": "/microdelivery",     "HasValue": true   } }</font></pre> </blockquote> <p>After calling the sample endpoint, we're going to publish an <strong>OrderShippedIntegrationEvent </strong>that will be handled by the Order's microservice to update the order, just subscribing to that event using the <strong>Topic </strong>attribute we already saw.</p> <blockquote> <pre><font color="#000000">[HttpPost("Ship") [Topic("rabbitmqpubsub", "OrderShippedEventTopic")] public async Task&lt;ActionResult&gt; OnOrderShippedEvent(OrderShippedIntegrationEvent orderShippedIntegrationEvent) { var order = await this.orderRepository .GetOrderAsync(orderShippedIntegrationEvent.OrderId); if (order is null) { return NotFound(); } order.ShippedAtUtc = orderShippedIntegrationEvent.ShippedAtUtc; await this.orderRepository.UpdateOrderAsync(order); return Ok(); }]</font></pre> </blockquote> <p>In the next article, we'll discuss about secret management with DAPR.</p><img src="http://blogs.ugidotnet.org/martinobordin/aggbug/102639.aspx" width="1" height="1" />Martino BordinWater in Wine with C#http://blogs.ugidotnet.org/leonardo/archive/2023/11/24/water-in-wine-csharp-array-cast.aspxFri, 24 Nov 2023 20:51:16 GMThttp://blogs.ugidotnet.org/leonardo/archive/2023/11/24/water-in-wine-csharp-array-cast.aspxhttp://blogs.ugidotnet.org/leonardo/comments/102638.aspxhttp://blogs.ugidotnet.org/leonardo/comments/commentRss/102638.aspxhttp://blogs.ugidotnet.org/leonardo/archive/2023/11/24/water-in-wine-csharp-array-cast.aspx#comment2http://blogs.ugidotnet.org/leonardo/services/trackbacks/102638.aspxWater in Wine with C#<div>A common need when working with images is to convert arrays containing pixels from a type to another.</div> <div><br /> </div> <div>For example an uint[] to byte[] conversion is common, but very slow and memory intensive.</div> <div><br /> </div> <div>Here the fastest method I developed for real-time applications:</div> <div><br /> </div> <div> <div><img src="/images/blogs_ugidotnet_org/leonardo/arrayCast.png" width="499" height="270" alt="" /></div> </div> <div><br /> </div> <div>The code is unsafe (additional testing recommended) and may not work with future CLR Runtimes, but it's pretty readable and fast.<br /> </div> <div><br /> </div> <div>In few words the code is changing the type of the array by overwriting the CLR Method Table and then resizing the array in a similiar way. A new array (of the desired type) pointing to the original one is then returned. The original data is never copied and this makes this method very fast to execute.<br /> </div> <div><br /> </div> <div>Here how to use the function CastArray:<br /> </div> <div><br /> </div> <div><img src="/images/blogs_ugidotnet_org/leonardo/arrayCastDemo.png" style="width: 368px; height: 80px;" alt="" /></div> <div><br /> </div> <div>An array containing a 4K 32 bit image can be casted with a great speedup compared to an Array copy with standard solutions such as Buffer.BlockCopy.<br /> </div> <div><br /> </div> <div>The drawback is that now we have overwritten the original array size and if we use the original array, we should manually ensure that we are not reading over it's end.</div> <div><br /> </div> <div>The byte[] is actually a reference array and changing it will change the uint[] (<span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span class="ryNqvb">and the opposite), but this can avoid further casts.</span></span></span></div> <div><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span class="ryNqvb"><br /> </span></span></span></div> <div><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span class="ryNqvb">Note: As I already done in the <a href="https://electro-logic.blogspot.com">electro-logic</a> blog, new posts starting from this one are only in </span></span></span><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span class="ryNqvb">English </span></span></span><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span class="ryNqvb">to enable more people to read them, but you can still contact me or leave a comment in Italian if you prefer.<br /> </span></span></span></div> <div><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span class="ryNqvb"><br /> </span></span></span></div> <div><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span class="ryNqvb">That's all for today</span></span></span></div><img src="http://blogs.ugidotnet.org/leonardo/aggbug/102638.aspx" width="1" height="1" />LeonardoDapr - Service invocation &amp; Pub/subhttp://blogs.ugidotnet.org/martinobordin/archive/2023/11/04/dapr-service-invocation-amp-pubsub.aspxSat, 04 Nov 2023 11:39:13 GMThttp://blogs.ugidotnet.org/martinobordin/archive/2023/11/04/dapr-service-invocation-amp-pubsub.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/102637.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/commentRss/102637.aspxhttp://blogs.ugidotnet.org/martinobordin/archive/2023/11/04/dapr-service-invocation-amp-pubsub.aspx#comment0http://blogs.ugidotnet.org/martinobordin/services/trackbacks/102637.aspxDapr - Service invocation &amp; Pub/sub<p>Dapr <a href="https://docs.dapr.io/developing-applications/building-blocks/service-invocation/service-invocation-overview/">service discovery &amp; invocation</a> is a feature that allows services to discover and call other services using HTTP or gRPC protocols, providing a simple and consistent way to invoke them.</p> <p>Communication is also</p> <ul> <li>secure (with mutual mTLS authentication) </li> <li>resilient (with configurable retry\circuit breaker\timeout policies) </li> <li>traced and metered (using common protocols) </li> <li>controlled (we can use ACL to restrict accesses\permissions to some APIs) </li> <li>balanced (using round-robin)</li> </ul> <p>The pub/sub is a messaging pattern where a message is published by a sender to a topic, and all the subscribers who have subscribed to that topic will receive a copy of the message. This allows loosely coupled communication between services, as the sender does not need to know who the receivers are or how many there are, and the subscribers do not need to know who the publisher is. </p> <p>The <a href="https://docs.dapr.io/developing-applications/building-blocks/pubsub/pubsub-overview/">pub/sub API in DAPR</a> provides a set of APIs that can be used to implement this pattern and allows developers to use different message brokers like Apache Kafka, RabbitMQ, Azure Service Bus, and many others. The API is platform-agnostic and offers an at least-once message delivery guarantee.</p> <p>Let's see how we can use both functionalities in the orders microservices.</p> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQFJ3X0LgtKEPw/article-inline_image-shrink_1500_2232/0/1681481079387?e=1704326400&amp;v=beta&amp;t=XfdVOt80FHKi4nlry6aEpDRJj9GTS6dPkNyq4zhCdvg" /></p> <p>As always, we have a standard API controller where we inject the <strong>DaprClient</strong>.</p> <p>The relevant code is in the <strong>SubmitOrder.</strong></p> <p>Essentially, what we want to do is:</p> <ul> <li>retrieve customer info (calling the customer's microservice) </li> <li>apply the current valid discount (calling the discount microservice) </li> <li>retrieve products info </li> <li>create and save a new order </li> <li>publish a message <strong>OrderSubmittedIntegrationEvent</strong></li> </ul> <p><strong /></p> <blockquote> <pre><font color="#000000">[HttpPost("Submit") [ProducesResponseType(typeof(Order), (int)HttpStatusCode.Created)] public async Task&lt;ActionResult&gt; SubmitOrder(SubmitOrderRequest request) { var customerInfo = await daprClient .InvokeMethodAsync&lt;CustomerInfo&gt;( HttpMethod.Get, "microdelivery-customers-api", $"customers/{request.CustomerId}"); if (customerInfo is null) { throw new Exception($"Customer {request.CustomerId} not found"); } var discount = await daprClient .InvokeMethodAsync&lt;int&gt;( HttpMethod.Get, "microdelivery-discount-api", "discount"); var order = new Order { CustomerId = customerInfo.Id, CustomerFirstName = customerInfo.FirstName, CustomerLastName = customerInfo.LastName, CustomerEmail = customerInfo.Email, TotalDiscount = discount }; var orderLineItems = new List&lt;OrderLineItem&gt;(); foreach (var requestOrderLineItem in request.OrderLineItems) { var productInfo = await daprClient .InvokeMethodAsync&lt;ProductInfo&gt;( HttpMethod.Get, "microdelivery-products-api", $"products/{requestOrderLineItem.ProductId}"); if (productInfo is null) { throw new Exception($"Product {requestOrderLineItem.ProductId} not found"); } var discountedPrice = discount == 0 ? productInfo.Price : productInfo.Price - (productInfo.Price * ((double)discount / 100)); var orderLineItem = new OrderLineItem { ProductId = productInfo.Id, ProductName = productInfo.Name, Price = productInfo.Price, DiscountedPrice = discountedPrice, Quantity = requestOrderLineItem.Quantity }; orderLineItems.Add(orderLineItem); } order.OrderLineItems = orderLineItems; await orderRepository.CreateOrderAsync(order); var orderSubmittedIntegrationEvent = new OrderSubmittedIntegrationEvent { OrderId = order.Id, CustomerId = order.CustomerId, CustomerFirstName = order.CustomerFirstName, CustomerLastName = order.CustomerLastName, CustomerEmail = order.CustomerEmail, TotalDiscount = order.TotalDiscount, OrderLineItems = order.OrderLineItems.Select(oli =&gt; new OrderSubmittedIntegrationEventLineItem { ProductId = oli.ProductId, ProductName = oli.ProductName, Quantity = oli.Quantity, Price = oli.Price, DiscountedPrice = oli.DiscountedPrice }) }; await daprClient.PublishEventAsync( "rabbitmqpubsub", "OrderSubmittedEventTopic", orderSubmittedIntegrationEvent); return CreatedAtAction(nameof(GetOrder), new { id = order.Id }, order); }</font></pre> </blockquote> <pre><br /></pre> <p>For the service invocation, we use the method <strong>InvokeMethodAsync&lt;T&gt; </strong>of the<strong> DaprClient</strong>.</p> <p>We have to specify the HTTP Verb to use, the application id of the other service (we set it on the sidecar configuration in the docker-compose file), and the method name. If the call is successful, we obtain the response of type T. That's simple.</p> <p>To publish a message, we use the method <strong>PublishEventAsync&lt;T&gt; </strong>of the <strong>DaprClient</strong>.</p> <p>We have to specify the name of the pubsub component, the topic where we want to publish the message, and the message payload.</p> <p>In our example, we're going to use RabbitMq, so here is the component specification:</p> <blockquote> <pre><font color="#000000">apiVersion: dapr.io/v1alpha kind: Component metadata:   name: rabbitmqpubsub spec:   type: pubsub.rabbitmq   version: v1   metadata:   - name: connectionString     value: "amqp://rabbit:5672"   - name: hostname     value: rabbit    - name: username     value: guest   - name: password     value: guest </font></pre> </blockquote> <pre><br /></pre> <pre>In the next article, we'll see how other services can subscribe to the published event in order to perform their logic.</pre><img src="http://blogs.ugidotnet.org/martinobordin/aggbug/102637.aspx" width="1" height="1" />Martino BordinDapr - Input Binding and Configurationhttp://blogs.ugidotnet.org/martinobordin/archive/2023/10/10/dapr-input-binding-and-configuration.aspxTue, 10 Oct 2023 06:37:44 GMThttp://blogs.ugidotnet.org/martinobordin/archive/2023/10/10/dapr-input-binding-and-configuration.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/102636.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/commentRss/102636.aspxhttp://blogs.ugidotnet.org/martinobordin/archive/2023/10/10/dapr-input-binding-and-configuration.aspx#comment0http://blogs.ugidotnet.org/martinobordin/services/trackbacks/102636.aspxDapr - Input Binding and Configuration<p>Dapr binding is a mechanism that allows connections between components and external services by providing a common interface for communication, without needing to know about each other's implementation details.</p> <p>It allows components to send and receive messages over a range of transport protocols and message brokers, like RabbitMQ and Kafka, Azure Event Grid, AWS SNS, Azure Service Bus, and Amazon SQS. You can also integrate with Twitter, SMTP, SendGrid, HTTP, or CRON.</p> <p>Dapr has a building block also to manage and retrieve the application configurations (settings, connection strings, identifiers, etc) just by configuring the related component.</p> <p>At the moment, the supported configuration stores are Redis, Postgres, and Azure App configuration.</p> <p>Let's see how we can use both functionalities in the discount microservices.</p> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQHp-_s1PT-Piw/article-inline_image-shrink_1500_2232/0/1681473637823?e=1702512000&amp;v=beta&amp;t=Zct7aIDDeegg0ovJFohGcOucXX56icn7q_7svSek_eA" /></p> <p>First of all, we have to reference an additional NuGet package: <strong>Dapr.Extensions.Configuration</strong></p> <p>Once done, just go to the Program.cs file and add these lines of code, where we declare the config store and the list of keys we want to retrieve.</p> <blockquote> <pre><font color="#000000">var builder = WebApplication.CreateBuilder(args var client = new <strong>DaprClientBuilder</strong>().Build(); builder.Configuration     .<strong>AddDaprConfigurationStore</strong>( "redisconfigstore", new List&lt;string&gt;() { "CrazyDiscountEnabled" }, client, TimeSpan.FromSeconds(20))     .<strong>AddStreamingDaprConfigurationStore</strong>( "redisconfigstore", new List&lt;string&gt;() { "CrazyDiscountEnabled" }, client, TimeSpan.FromSeconds(20));)</font></pre> </blockquote> <pre><font color="#000000"><br /></font></pre> <p>Please note that <em>AddDaprConfigurationStore </em>will make the first call to load the config with the given keys, while <em>AddStreamingDaprConfigurationStore </em>will keep watching for changes and update local configurations.</p> <p>Here's the main code of the discount controller:</p> <blockquote> <pre><font color="#000000">[ApiController [Route("[controller]")] public class DiscountController : ControllerBase { private readonly DaprClient daprClient; private readonly IConfiguration configuration; public DiscountController( DaprClient daprClient, IConfiguration configuration) { this.daprClient = daprClient; this.configuration = configuration; } [HttpPost("/discountcronbinding")] public async Task&lt;ActionResult&gt; UpdateDiscount() { var crazyDiscountEnabled = configuration .GetValue&lt;bool&gt;("CrazyDiscountEnabled"); if (!crazyDiscountEnabled) { return Ok(); } var random = new Random(Guid.NewGuid().GetHashCode()); var discount = random.Next(1, 30); await daprClient.SaveStateAsync("redisstore", "CrazyDiscountValue", discount); return Ok(); } [HttpGet] public async Task&lt;int&gt; GetDiscount() { var discount = 0;          var crazyDiscountEnabled = configuration .GetValue&lt;bool&gt;("CrazyDiscountEnabled");         if (crazyDiscountEnabled)         {          discount = await daprClient .GetStateAsync&lt;int&gt;("redisstore", "CrazyDiscountValue");         } return discount; } }]</font></pre> </blockquote> <p>We have a standard API Controller where we inject the DaprClient and the standard <em>IConfiguration </em>object that allows us to retrieve the settings.</p> <p>The <strong>UpdateDiscount</strong> method checks if the configuration with the key <strong>CrazyDiscountEnabled</strong> is enabled. If yes, we're going to generate a random discount and save it using the state management we already know.</p> <p>How is configured the Config store? Using the component specification, of course!</p> <blockquote> <pre><font color="#000000">apiVersion: dapr.io/v1alpha kind: Component metadata:   name: redisconfigstore spec:   type: configuration.redis   metadata:   - name: redisHost     value: redis:63791</font></pre> </blockquote> <pre><br /></pre> <pre><br /></pre> <pre>As you can see we're connecting to Redis, so we can enable the crazy discount feature by running the following command in the Redis CLI</pre> <pre><br /></pre> <blockquote> <pre><font color="#000000">SET CrazyDiscountEnabled true</font></pre> </blockquote> <p>Now the random discount calculation is enabled, but when and who is calling this API?</p> <p>We're going to use the <a href="https://docs.dapr.io/reference/components-reference/supported-bindings/cron/">CRON input binding</a>, which will trigger a POST request based on the CRON expression we specify.</p> <p>Here is our configuration:</p> <blockquote> <pre><font color="#000000">apiVersion: dapr.io/v1alpha kind: Component metadata:   name: discountcronbinding spec:   type: bindings.cron   version: v1   metadata:   - name: schedule     value: "* * * * * *"</font></pre> </blockquote> <pre><br /></pre> <p>We set the CRON expression in order to trigger every second. The POST will call a method with the same name as the binding (<strong>discountcronbinding </strong>in our case). So, basically, we're calculating a new random discount every second (if enabled by config).</p> <p>We can retrieve the current valid discount just by performing a GET request to the Discount endpoint.</p> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQGU7RzuwqH6lg/article-inline_image-shrink_1500_2232/0/1681480158825?e=1702512000&amp;v=beta&amp;t=jxITQdtKD2q4yHKqHoyCvP-5XqQe9J6owlMzopTLEdI" /></p> <p>In the next article, we'll see the Pub\Sub building block.</p><img src="http://blogs.ugidotnet.org/martinobordin/aggbug/102636.aspx" width="1" height="1" />Martino BordinDapr - State managementhttp://blogs.ugidotnet.org/martinobordin/archive/2023/09/06/dapr-state-management.aspxWed, 06 Sep 2023 13:54:07 GMThttp://blogs.ugidotnet.org/martinobordin/archive/2023/09/06/dapr-state-management.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/102632.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/commentRss/102632.aspxhttp://blogs.ugidotnet.org/martinobordin/archive/2023/09/06/dapr-state-management.aspx#comment0http://blogs.ugidotnet.org/martinobordin/services/trackbacks/102632.aspxDapr - State management<p>Dapr allows the storage of durable data (key\value pairs) across multiple sessions and services.</p> <p>With Dapr State Management, you can:</p> <ul> <li>Save and retrieve state using different stores with 2 levels of consistency (strong and eventual) </li> <li>Use a consistent API to perform operations, abstracting away the implementation details. </li> <li>Implement caching (with TTL) to improve performance. </li> <li>Filter\Sort\Page state entries</li> </ul> <p>Let's see how we can use it in the customer's microservices.</p> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQHDKs12V7_WGQ/article-inline_image-shrink_1500_2232/0/1681464150319?e=1699488000&amp;v=beta&amp;t=-5fQ12_z-z-IiYVK2ZlQNwtZNtnlNb6Cu7DRwzJy6n4" /></p> <p>The customers' microservice persists data in MS SQL Server and caches data in MongoDB</p> <p>Here's the code:</p> <blockquote> <pre><font color="#000000">public class CustomersController : ControllerBase { private readonly ILogger&lt;CustomersController&gt; logger; private readonly DaprClient daprClient; private readonly ICustomersRepository customerRepository; public CustomersController(ILogger&lt;CustomersController&gt; logger, DaprClient daprClient, ICustomersRepository customerRepository) { this.logger = logger; this.daprClient = daprClient; this.customerRepository = customerRepository; } [HttpGet] [ProducesResponseType(typeof(IEnumerable&lt;Customer&gt;), (int)HttpStatusCode.OK)] public async Task&lt;ActionResult&lt;IEnumerable&lt;Customer&gt;&gt;&gt; GetCustomers() { var customers = await GetCustomersFromCache(); return Ok(customers); } private async Task&lt;IEnumerable&lt;Customer&gt;&gt; GetCustomersFromCache() { var customers = await daprClient .GetStateAsync&lt;IEnumerable&lt;Customer&gt;&gt;( "mongostore", "GetCustomers"); if (customers == null) { customers = await customerRepository .GetCustomersAsync(); await daprClient .SaveStateAsync("mongostore", "GetCustomers", customers); } return customers; } }</font> </pre> </blockquote> <p>We have a standard API Controller where we inject the <strong>DaprClient </strong>(view the previous article to see the NuGet package required and how to register it).</p> <p>In the <strong>GetCustomersFromCache </strong>method, we use the <strong>GetStateAsync </strong>to check if we previously cached the data. If yes, we just return it; if no, we load it (using the customer repository), cache it using the <strong>SaveStateAsync </strong>and return it.</p> <p>Please note that we are specifying where we want to save our state by passing the store name (in our case "mongostore"). But where is it defined?</p> <p>If you remember in the previous article we configured the sidecar with the component path; that's the folder where we store the configurations of our components.</p> <p>Therefore, we just have to create under that folder a new YAML file with the following configuration</p> <blockquote> <pre><font color="#000000">apiVersion: dapr.io/v1alpha kind: Component metadata:   name: mongostore spec:   type: state.mongodb   version: v1   metadata:   - name: host     value: "mongo:27017"</font></pre> </blockquote> <p>The value "mongostore" in the metadata section is the store name we have to use in our code (I set it as "mongostore", but you can follow your preferred naming convention). We also specify how to connect to the MongoDB store.</p> <p>Where can you find all these settings? In the <a href="https://docs.dapr.io/reference/components-reference/supported-state-stores/setup-mongodb/">official documentation</a>, of course!</p> <p>Now we have all the information to use another state store (i.e. Redis) as I've done in the products microservice.</p> <p>The products' microservice persists data in PostgreSQL and cache data in Redis</p> <p>The relevant piece of code is similar to the previous one:</p> <blockquote> <pre><font color="#000000">private async Task&lt;IEnumerable&lt;Product&gt;&gt; GetProductsFromCache( { var products = await daprClient .GetStateAsync&lt;IEnumerable&lt;Product&gt;&gt;( "redisstore", "GetProducts"); if (products == null) { products = await this.productRepository.GetProductsAsync(); await daprClient.SaveStateAsync("redisstore", "GetProducts", products); } return products; })</font></pre> </blockquote> <p>To configure the Redis state store, we create the following file in the component's folder</p> <blockquote> <pre><font color="#000000">apiVersion: dapr.io/v1alpha kind: Component metadata:   name: redisstore spec:   type: state.redis   version: v1   metadata:   - name: redisHost     value: redis:6379   - name: redisPassword     value: ""</font></pre> </blockquote> <p>To test both customers' and products' microservices, I prepared 2 <em>.http</em> files with the sample GET requests, so we can use Visual Studio.</p> <p>Just start the solution (using the docker-compose) and executes both requests.</p> <p>When executing the GET /customers, the result will be cached in Mongo</p> <p>In the <a href="https://github.com/martinobordin/MicroDelivery">source code</a> on GitHub, you can see also how to delete the state and how to set a TTL of the cached value (otherwise cache will never expire!).</p> <p>In the next article, we'll see the Configuration and Binding building blocks</p><img src="http://blogs.ugidotnet.org/martinobordin/aggbug/102632.aspx" width="1" height="1" />Martino BordinDapr - Create a Dapr servicehttp://blogs.ugidotnet.org/martinobordin/archive/2023/07/03/dapr-create-a-dapr-service.aspxMon, 03 Jul 2023 05:19:37 GMThttp://blogs.ugidotnet.org/martinobordin/archive/2023/07/03/dapr-create-a-dapr-service.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/102631.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/commentRss/102631.aspxhttp://blogs.ugidotnet.org/martinobordin/archive/2023/07/03/dapr-create-a-dapr-service.aspx#comment0http://blogs.ugidotnet.org/martinobordin/services/trackbacks/102631.aspxDapr - Create a Dapr service<p>In order to use Dapr with C#, you just have to create a new ASP.NET Core Web API Project and reference the Nuget package <strong>Dapr.AspNetCore</strong></p> <p>Once done, just go in the <em>Program.cs</em> and chain the method <strong>AddDapr()</strong> after the method <strong>AddControllers()</strong>:</p> <blockquote> <pre><font color="#000000">builder.Services.AddControllers().AddDapr();</font></pre> </blockquote> <pre><font color="#000000"><br /></font></pre> <pre>In addition to that, just call these methods to register the Pub\Sub building block:</pre> <pre><br /></pre> <blockquote> <pre><font color="#000000">app.MapSubscribeHandler(); app.UseCloudEvents();</font></pre> </blockquote> <pre><br /></pre> <pre>At this point, you can inject the <strong>DaprClient</strong>, in your controller or services<strong>, </strong>to interact with the several APIs of Dapr.</pre> <pre><br /></pre> <blockquote> <pre><font color="#000000">public CustomersController(DaprClient daprClient) { this.daprClient = daprClient; }</font></pre> </blockquote> <pre><br /></pre> <pre><br /></pre> <pre>We then can run the application along with Dapr sidecar using the CLI</pre> <pre><br /></pre> <blockquote> <pre><font color="#000000">dapr run --app-id microdelivery.customers.api --app-port 8000 -- dotnet run</font></pre> </blockquote> <pre><br /></pre> <pre>But, since we're going to create several microservices, I prefer the <a href="https://docs.dapr.io/operations/hosting/self-hosted/self-hosted-with-docker/#run-using-docker-compose">docker-compose</a> approach. Here the YAML file for the customer's microservice (<em>microdelivery.customers.api</em>) and its sidercar (<em>microdelivery.customers.api.dapr</em>).</pre> <pre><br /></pre> <blockquote> <pre><font color="#000000"> version: '3.4 services: # Customers Api &amp; Sidecar microdelivery.customers.api: container_name: microdelivery.customers.api image: ${DOCKER_REGISTRY-}microdeliverycustomersapi build: context: . dockerfile: src/MicroDelivery.Customers.Api/Dockerfile depends_on: - sqlserver - redis environment: - ASPNETCORE_ENVIRONMENT=Development ports: - "8000:80" microdelivery.customers.api.dapr: container_name: microdelivery.customers.api.dapr image: "daprio/daprd:latest" network_mode: "service:microdelivery.customers.api" depends_on: - microdelivery.customers.api command: ["./daprd", "-app-id", "microdelivery-customers-api", "-app-port", "80", "-resources-path", "/components", "-config", "/configuration/configuration.yaml", "-log-level", "debug" ] volumes: - "./dapr/components/:/components" - "./dapr/configuration/:/configuration"' </font></pre> </blockquote> <p>The sidecar is a docker image (<em>daprio/daprd</em>) attached to the network of the customer's microservices where we execute the daprd command, passing some parameters like the app id that identifies our app, the app port, what is the components\config path to customize our microservices behavior and the log level.</p> <p>We can then just run the application with Visual Studio that will create the two containers and we're ready to debug it!</p> <p>In the next article, we'll see the first building block: <strong>State management</strong></p><img src="http://blogs.ugidotnet.org/martinobordin/aggbug/102631.aspx" width="1" height="1" />Martino BordinDapr - The application scenariohttp://blogs.ugidotnet.org/martinobordin/archive/2023/09/06/dapr-the-application-scenario.aspxWed, 06 Sep 2023 14:12:45 GMThttp://blogs.ugidotnet.org/martinobordin/archive/2023/09/06/dapr-the-application-scenario.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/102633.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/commentRss/102633.aspxhttp://blogs.ugidotnet.org/martinobordin/archive/2023/09/06/dapr-the-application-scenario.aspx#comment0http://blogs.ugidotnet.org/martinobordin/services/trackbacks/102633.aspxDapr - The application scenario<p>In this series of articles (source code is available on <a href="https://github.com/martinobordin/MicroDelivery">GitHub</a>), we'll develop a microservices application for an imaginary food delivery company called "MicroDelivery".</p> <p>We'll have several services, each with its own logic, that will interact via RPC call or pub\sub messaging and we'll see how to use Dapr to build it.</p> <hr /> <p><strong>⚠️ Disclaimer</strong></p> <p> My goal here is to give you a birds-eye view of the different features of Dapr, not to guide you step by step on building an application from scratch, nor to explain the single details of Dapr (there's the official website and several books for that!)</p> <p> I won't explain why and when to adopt a microservices architecture and related pros\cons, nor we'll talk about any design\integrations\architectural patterns.</p> <p>☁️We're not going to use any Cloud Provider (only on-prem docker services), but of course, the nature of Dapr allows you to easily switch from on-prem to the cloud.</p> <p>⚒️ The application leverages several technologies(Redis, RabbitMq, SqlServer, PostgreSQL, MongoDB, Zipkin) and shows you how it's simple to use them together with Dapr. Of course, in the real world, you need to analyze your requirements and understand if these tools are useful for your needs along with their strong and weak points.</p> <hr /> <h5>Customers Microservice</h5> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQHAFHqQPWR6zQ/article-inline_image-shrink_1500_2232/0/1680628260512?e=1699488000&amp;v=beta&amp;t=eQTPc1fRCVieq9qMun3KNJQJqDe7lN95Ey3UY_vSLMk" /></p> <p>Customers Microservice</p> <p>It's a CRUD microservice to manage customers' data.</p> <p>It persists its data in <em>SQL Server</em> using <em>Entity Framework</em> and caches them in <em>MongoDB</em>, using Dapr State block</p> <h5>Products Microservice</h5> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQEKSCWPZelD3g/article-inline_image-shrink_1500_2232/0/1680628274156?e=1699488000&amp;v=beta&amp;t=i1zzNSBkhFzV6lAWDuYNtnjLHFZSF0PZaRQZCmfRDHY" /></p> <p>Products Microservice</p> <p>It's a CRUD microservice to manage products' data.</p> <p>It persists its data in <em>PostgreSQL </em>using <em>Entity Framework</em> and caches them in <em>Redis </em>using Dapr State block</p> <h5>Orders Microservice</h5> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQGDs0MRDxZApA/article-inline_image-shrink_1500_2232/0/1680628286297?e=1699488000&amp;v=beta&amp;t=f-pP8ch8lPIjsAvBMaLDnArM7dAU1MjXsqZSRdtar8M" /></p> <p>Orders Microservice</p> <p>It's a microservice that receives the order requests, performs some, publishes a message (<em>OrderSubmittedEvent</em>) to notify other services, and receives a message (<em>OrderShipped</em>) to mark an order as shipped.</p> <p>It persists its data in <em>MongoDB</em>, calls Discount\ Customers\Products microservices using service-to-service DAPR block, and send\received message in <em>RabbitMQ </em>using Dapr <em>Pub\Sub</em> block,</p> <h5>Discount Microservice</h5> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQHGsgsLGzHmmw/article-inline_image-shrink_1500_2232/0/1680628300423?e=1699488000&amp;v=beta&amp;t=NyJ7jua90hdoP_GUWueAedSM2IDowrI5Obcu0UmHa3o" /></p> <p>Discount Microservice</p> <p>It's a microservice that, if enabled by configuration, calculates a random discount (very funny, isn't it?) that remains valid until the next recalculation.</p> <p>The (re)calculation is triggered by a <em>Dapr CRON Binding</em>, and the configuration is stored on the <em>Redis </em>configuration block. It will be invoked by the Orders microservice using <em>Dapr service-to-service</em> communication,</p> <h5>Notifications Microservice</h5> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D5612AQGfkYGn4EjUbQ/article-inline_image-shrink_1500_2232/0/1680798586612?e=1699488000&amp;v=beta&amp;t=l8JiVFzltWwtcLRVq4vMXOKdHrikjFfWO-xD_frUEJQ" /></p> <p>Notifications Microservice</p> <p>It's a microservice that receives the message <em>OrderSubmittedEvent </em>and sends a confirmation email to customers, using <em>Dapr SMTP binding</em>.</p> <h5>Shipping Microservice</h5> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQGyI2KDYnYMBg/article-inline_image-shrink_1500_2232/0/1680628333186?e=1699488000&amp;v=beta&amp;t=VBI04z0UmH2fPWSWHVEsgDI0WxQAolig5fT8dQIwbLk" /></p> <p>Shipping Microservice</p> <p>It's a microservice that receives the message <em>OrderSubmittedEvent </em>and performs an HTTP call to an external Webhook, using <em>Dapr HTTP binding </em>and reading the Bearer Token from <em>Dapr Secret store</em>. It will also publish an <em>OrderShipped </em>event.</p> <p>Here is the full application diagram</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/martinobordin/Open-Live-Writer/Dapr---The-application-scenario_FF38/123_2.png"><img title="123" style="display: inline; background-image: none;" border="0" alt="123" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/martinobordin/Open-Live-Writer/Dapr---The-application-scenario_FF38/123_thumb.png" width="757" height="966" /></a></p> <p>A full diagram of the sample application</p> <p>The dotted links are the calls to Dapr Sidecar, performed using the C# SDK.</p> <p>In the next article, we'll see how to set up Dapr within our project.</p><img src="http://blogs.ugidotnet.org/martinobordin/aggbug/102633.aspx" width="1" height="1" />Martino BordinDapr - An introduction to the runtimehttp://blogs.ugidotnet.org/martinobordin/archive/2023/09/06/dapr-an-introduction-to-the-runtime.aspxWed, 06 Sep 2023 14:20:48 GMThttp://blogs.ugidotnet.org/martinobordin/archive/2023/09/06/dapr-an-introduction-to-the-runtime.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/102635.aspxhttp://blogs.ugidotnet.org/martinobordin/comments/commentRss/102635.aspxhttp://blogs.ugidotnet.org/martinobordin/archive/2023/09/06/dapr-an-introduction-to-the-runtime.aspx#comment0http://blogs.ugidotnet.org/martinobordin/services/trackbacks/102635.aspxDapr - An introduction to the runtime<p><strong>Dapr</strong>, standing for <strong>D</strong>istributed <strong>Ap</strong>plication <strong>R</strong>untime, is an open-source event-driven runtime that simplifies the building of resilient microservices-based applications.</p> <p>It's designed to work with any programming language, any infrastructure, and any cloud provider (Azure, AWS, GCP) and it's part of the Cloud Native Computing Foundation (<a href="https://www.cncf.io/projects/dapr/">CNCF</a>) project.</p> <p>Its main goal is to abstract the complexity of distributed systems and allows developers to focus on business logic rather than the underlying infrastructure (warning: just because the complexity is 'hidden' doesn't mean you should not be aware of what it is and how you would solve it).</p> <p>These abstractions are called 'Building blocks' and provide APIs for common functionalities like State Management, Service Discovery &amp; Invocation, Publish &amp; Subscribe, Observability, and many others.</p> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQEE3SsjDLiQiA/article-inline_image-shrink_1000_1488/0/1679478440760?e=1698883200&amp;v=beta&amp;t=EHujRS7Yqdi09r6Ri_PVFnRilSrxNHBdFCmJ9WkZVmc" /></p> <p>The implementation of a building block is called 'component' and there are several of them ready to use, all configurable using external YAML files and all easily interchangeable.</p> <p>For example, for the publish\subscribe feature, we have components for RabbitMQ, Redis, AWS SNS/SQS, or GCP Pub/Sub.</p> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQGzobInNEC9cQ/article-inline_image-shrink_1000_1488/0/1680528577759?e=1698883200&amp;v=beta&amp;t=6m3i1MncIvpxIQIhrXJoedVcz2uekg1AE_iAxha5lEU" /></p> <p>Dapr will run as an external process\container (called <a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/sidecar">Sidecar</a>) and our application will interact with it using HTTP\GRPC or the SDKs available for the main programming languages (.NET, Java, Node, Python, Go).</p> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQFSDy_wMIMBgQ/article-inline_image-shrink_1500_2232/0/1679485689192?e=1698883200&amp;v=beta&amp;t=ozjf_RdA8Y71Qx_n3c76-5BBDjPsdHC8aXw8F60vD0o" width="866" height="495" /></p> <p>We can also use a CLI and a Dashboard to initialize, run, and tests Dapr applications.</p> <p><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQHzL-aAu9b3yg/article-inline_image-shrink_1000_1488/0/1679487782486?e=1698883200&amp;v=beta&amp;t=F0dN9nTKU1KSPirKiQPuTGPUM8Cnj7Zwvl9rpGF2Fqs" /><img alt="No alt text provided for this image" src="https://media.licdn.com/dms/image/D4D12AQHEOXMok3DKmg/article-inline_image-shrink_1000_1488/0/1679487820188?e=1698883200&amp;v=beta&amp;t=OlTnOrCwvrth028HVy_vBxPpzjjDwBPq9-baBs2-Ew0" /></p> <p>You can read the full documentation on the <a href="https://dapr.io/">official website</a>.</p> <p>In the next article, we'll see how we can build a sample application using DAPR.</p><img src="http://blogs.ugidotnet.org/martinobordin/aggbug/102635.aspx" width="1" height="1" />Martino BordinWPF ed i 0.01 DPI mancantihttp://blogs.ugidotnet.org/leonardo/archive/2023/03/24/wpf-ed-i-0-01-dpi-mancanti.aspxFri, 24 Mar 2023 00:18:53 GMThttp://blogs.ugidotnet.org/leonardo/archive/2023/03/24/wpf-ed-i-0-01-dpi-mancanti.aspxhttp://blogs.ugidotnet.org/leonardo/comments/102627.aspxhttp://blogs.ugidotnet.org/leonardo/comments/commentRss/102627.aspxhttp://blogs.ugidotnet.org/leonardo/archive/2023/03/24/wpf-ed-i-0-01-dpi-mancanti.aspx#comment3http://blogs.ugidotnet.org/leonardo/services/trackbacks/102627.aspxWPF ed i 0.01 DPI mancanti<div>Una caratteristica di WPF e' l'indipendenza dalla risoluzione, in particolare le immagini bitmap vengono automaticamente ridimensionate a <span style="font-weight: bold;">96 DPI</span>, valore di default storico di Windows.<br /> </div> <div><br /> </div> <div>Un'immagine 512x512 pixel a 72 DPI verra' quindi ridimensionata a 682.5 x 682.5 pixel circa. Questo succedera' indipendentemente dai DPI impostati nel sistema.<br /> </div> <div><br /> </div> <div>Utilizzando software professionali di editing di immagini come Adobe Photoshop, Gimp, etc.. e' possibile salvare i nostri capolavori con una risoluzione DPI specifica. Questa informazione (DpiX e DpiY) non modifica di fatto la dimensione in pixel dell'immagine, ma e' un attributo che viene salvato nei metadati del file e che puo' essere per esempio utile in fase di stampa... e in WPF.</div> <div><br /> </div> <div>Soddisfatti della nostra creazione, impostiamo quindi 96 DPI, certi che la nostra immagine non verra' <span style="font-weight: bold;">mai e poi mai</span> ridimensionata, ed aggiungiamo il seguente codice XAML alla nostra pagina:</div> <div><br /> </div> <div><img src="/images/blogs_ugidotnet_org/leonardo/dpi/xaml.png" style="width: 405px; height: 107px;" alt="" /></div> <div><br /> </div> <div>La nostra immagine e' stata inserita in un controllo Viewbox a scopo dimostrativo per <span style="font-weight: bold;">evitare </span>ridimensionamenti dovuti a limiti di spazio della <span style="font-style: italic;">Window</span>, selezionando il controllo <span style="font-style: italic;">Image </span>notiamo pero' qualcosa di strano nel pannello delle proprieta' di Visual Studio.</div> <div><br /> </div> <div><img src="/images/blogs_ugidotnet_org/leonardo/dpi/size.png" style="width: 284px; height: 189px;" alt="" /></div> <div><br /> </div> <div>L'immagine e' stata ridimensionata da WPF! Il nostro castello di carte e' cascato dalle fondamenta, manca circa 0.1 pixel per lato!</div> <div><br /> </div> <div>Questo puo' essere un problema trascurabile dal punto di vista grafico e prestazionale, ma cerchiamo ad ogni modo di <span style="font-weight: bold;">capire</span> cosa sta succendo.</div> <div><br /> </div> <div>Eseguendo il seguente codice C#<br /> </div> <div><br /> </div> <div><img src="/images/blogs_ugidotnet_org/leonardo/dpi/dpi.png" style="width: 273px; height: 42px;" alt="" /></div> <div><br /> </div> <div>scopriamo una triste realta' che stravolgera' presto tutte le nostre certezze. L'immagine e' di fatto a<span style="font-weight: bold;"> 96.01 DPI</span>!</div> <div><br /> </div> <div>Adobe e' impazzita? un Easter Eggs di Gimp? Un complotto di Visual Studio?<br /> </div> <div><br /> </div> <div>Vediamo quindi di fare chiarezza, il formato <span style="font-weight: bold;">PNG </span>salva la risoluzione in un chunk chiamato <span style="font-weight: bold;">Physical pixel dimensions</span> (pHYs) composto da tre campi:</div> <div><br /> </div> <div>- Pixels per unit, x axis (4 bytes, unsigned integer)<br /> - Pixels per unit, y axis (4 bytes, unsigned integer)<br /> - Unit specifier (1 byte)</div> <div><br /> </div> <div>dove lo <a href="https://www.w3.org/TR/png/#11pHYs">standard </a>definisce come unita' valide solamente il metro o l'unita' indefinita. Il metro e' definito anche dal SI (Sistema Internazionale di unita' di misura), quindi a prima vista ha senso impiegarlo in uno standard al posto dei piedi o di altre unita' meno blasonate.<br /> </div> <div><br /> </div> <div>Utilizzando il metro stiamo quindi parlando di DPM (Dot per Meter). Un DPM equivale a 0.0254 DPI e sfortuna vuola che i campi prevedano solamente valori interi. <br /> </div> <div><br /> </div> <div>3779 DPM equivalgono a circa 95.99 DPI mentre <span style="font-weight: bold;">3780 </span>a circa 96.01 DPI. <span style="font-weight: bold;">Non </span>esiste modo di specificare 96 DPI precisi, 0.01 DPI saranno sempre mancanti.</div> <div><br /> </div> <div><span style="font-weight: bold; font-style: italic; text-decoration: underline;">NB</span>: Molti software arrotondano i valori di DPI visualizzati, prestare quindi sempre la massima attenzione. </div> <div><br /> </div> <div>Questo e' un bel <span style="font-weight: bold;">dilemma </span>per WPF, che di default usa proprio 96 DPI per le immagini, anche se a dire il vero non ho visto insurrezioni popolari in questi anni. <br /> </div> <div><br /> </div> <div>Un software utile per analizzare (e modificare) i metadati dei file PNG e' <a href="https://entropymine.com/jason/tweakpng/">TweakPNG</a>, dove a prima vista i nostri sogni di perfezione DPI-eggianti tornano, per poi svanire all'amara realta' con un doppio click.<br /> </div> <div><br /> </div> <div><img src="/images/blogs_ugidotnet_org/leonardo/dpi/tweakpng.png" alt="" width="500" height="262" /><br /> </div> <div><br /> </div> <div><br /> </div> <div><span style="font-weight: bold; font-style: italic; text-decoration: underline;">NB:</span> Questo problema non affligge il formato TIFF dove l'unita' di risoluzione puo' essere impostata in pollici (inch).</div> <div><br /> </div> <div>Per motivi di orgoglio piu' che tecnici non vogliamo pero' convertire tutte le nostre icone al formato TIFF, cosa possiamo dunque fare?</div> <div><br /> </div> <div>La matematica non lascio molto scampo, ma la fantasia ha ancora qualche carta da giocare.<br /> </div> <div><br /> </div> <div>Per risolvere il problema possiamo procedere in due modi:</div> <div><br /> </div> <div>- cancellare il <span style="font-weight: bold;">chunk pHYs</span> (che e' opzionale) se creato dall'app di editing grafico.<br /> </div> <div><br /> </div> <div>- impostare ad "unspecified units" l'unita' di misura. I valori X ed Y verranno ignorati.</div> <div><br /> </div> <div>Entrambe queste soluzioni forzeranno a 96 DPI esatti la risoluzione dell'immagine in WPF ed eviteranno qualsiasi ridimensionamente.</div> <div><br /> </div> <div>Personalmente preferisco utilizzare utility come <a href="https://pnggauntlet.com/">PNGGauntlet </a>che eliminano i chunk opzionali ed ottimizzano la dimensione del file (senza perdita di dati). Molto utile anche per evitare errori "App manifest references .. which is larger than the maximum image file size." durante il packaging di applicazioni UWP.<br /> </div> <div><br /> </div> <div>Avete mai notato che i 96 DPI esatti non esistono nei formati PNG e BMP? Dite la vostra nei commenti ed un saluto a tutti!<br /> </div> <div><br /> </div> <div><span style="font-weight: bold; font-style: italic; text-decoration: underline;">NB:</span> Gli stessi concetti posso applicarsi ad altre tecnologie basate su XAML come ad esempio UWP<br /> </div><img src="http://blogs.ugidotnet.org/leonardo/aggbug/102627.aspx" width="1" height="1" />LeonardoPer chiudere il cerchio 2004-2021 sulla Complessitàhttp://blogs.ugidotnet.org/luKa/archive/2021/12/21/per-chidere-il-cerchio-2004-2021-sulla-complessita.aspxTue, 21 Dec 2021 10:31:45 GMThttp://blogs.ugidotnet.org/luKa/archive/2021/12/21/per-chidere-il-cerchio-2004-2021-sulla-complessita.aspxhttp://blogs.ugidotnet.org/luKa/comments/102626.aspxhttp://blogs.ugidotnet.org/luKa/comments/commentRss/102626.aspxhttp://blogs.ugidotnet.org/luKa/archive/2021/12/21/per-chidere-il-cerchio-2004-2021-sulla-complessita.aspx#comment0http://blogs.ugidotnet.org/luKa/services/trackbacks/102626.aspxPer chiudere il cerchio 2004-2021 sulla Complessità<div><br /> </div> <div><br /> </div> Un video per condividere le lezioni che ho imparato e maturato,  a partire dalla proma Keynote di Joseph Pelrine al Agile Day nel 2004.<br /> <div><br /> </div> <div>E il relativo <a href="https://leanpub.com/livingcomplexity/">ebook Living Complexity.<br /> </a></div> <div><br /> </div> <div><br /> </div> <div><br /> <div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/649159298?h=cdbf5ca8f6&amp;title=0&amp;byline=0" style="position:absolute;top:0;left:0;width:100%;height:100%;" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen="" frameborder="0"></iframe></div> <script src="https://player.vimeo.com/api/player.js"></script> <p><a href="https://vimeo.com/649159298">Applicazioni pratiche della Complessità nello sviluppo software &amp; di prodotti digitali - Luca Minudel</a> from <a href="https://vimeo.com/italianagileday">Italian Agile Movement</a> on <a href="https://vimeo.com">Vimeo</a>.</p> <p>Questa sessione illustra un panorama di pratiche ispirate dalla Human-Complexity che possono essere usate ogni giorno nello sviluppo software e di prodotti digitali. Viene presentato anche un nuovo approccio per adottare Human-Complexity thinking per farsi strada verso il nuovo modo di pensare attraverso la pratica.</p> </div> <div><br /> </div><img src="http://blogs.ugidotnet.org/luKa/aggbug/102626.aspx" width="1" height="1" />Luca MinudelSummer 2021 reading listhttp://blogs.ugidotnet.org/luKa/archive/2021/07/21/summer-2021-reading-list.aspxWed, 21 Jul 2021 16:30:03 GMThttp://blogs.ugidotnet.org/luKa/archive/2021/07/21/summer-2021-reading-list.aspxhttp://blogs.ugidotnet.org/luKa/comments/102625.aspxhttp://blogs.ugidotnet.org/luKa/comments/commentRss/102625.aspxhttp://blogs.ugidotnet.org/luKa/archive/2021/07/21/summer-2021-reading-list.aspx#comment0http://blogs.ugidotnet.org/luKa/services/trackbacks/102625.aspxSummer 2021 reading list<div>Quest'anno come reading-list propongo un libro che ho scritto.</div> <div>Non è come un romanzo di Camilleri, ma anche per i piu esperti di Agile contiene concetti e modelli sconosciuti a molti.<br /> E per molti che lavorano in varie aziende contiene idee che potrebbero essere 20 anni avanti a alcuni dei modi di pensare consolidati.<br /> <br /> Vado oltre il fatto che trovo di cattivo gusto fare questa forma di auto-promozione qui solo per il fatto che il contenuto di questo libro è maturato in un contesto particolare all'estero e credo che condividere queste idee nuove e avanzate con chi opera in un contesto prevalentemente Italiano possa essere molto utile: <a href="https://leanpub.com/livingcomplexity/">Living Complexity</a><br /> </div> <div><br /> </div> <div><br /> </div> <div style="text-align: center;"><a href="https://leanpub.com/livingcomplexity/"><img src="/images/blogs_ugidotnet_org/luKa/CVPpng thumbnail.png" style="width: 238px; height: 358px;" alt="" /></a><br /> </div> <div><br /> </div><img src="http://blogs.ugidotnet.org/luKa/aggbug/102625.aspx" width="1" height="1" />Luca MinudelCloud Champions: storie di cloud, raccontate dai suoi protagonistihttp://blogs.ugidotnet.org/pape/archive/2021/03/16/cloud-champions-storie-di-cloud-raccontate-dai-suoi-protagonisti.aspxTue, 16 Mar 2021 12:44:51 GMThttp://blogs.ugidotnet.org/pape/archive/2021/03/16/cloud-champions-storie-di-cloud-raccontate-dai-suoi-protagonisti.aspxhttp://blogs.ugidotnet.org/pape/comments/102624.aspxhttp://blogs.ugidotnet.org/pape/comments/commentRss/102624.aspxhttp://blogs.ugidotnet.org/pape/archive/2021/03/16/cloud-champions-storie-di-cloud-raccontate-dai-suoi-protagonisti.aspx#comment0http://blogs.ugidotnet.org/pape/services/trackbacks/102624.aspxCloud Champions: storie di cloud, raccontate dai suoi protagonisti<p>Stasera inizio una nuova avventura, si chiama <strong>"Cloud Champions"</strong> e consiste in una serie di interviste (trasmesse in live streaming) a persone insieme alle quali cercherò di comunicare perché "cloud" non è "hosting 2.0" ma molto di più.</p> <p>È per questo motivo che gli episodi saranno sia tecnici sia "business" o esperienziali perché, ormai, "cloud" è sia una piattaforma che permette a sviluppatori ed imprenditori di avvalersi di una piattaforma elastica nelle performance e nei costi, sia l'infrastruttura che permette a noi utenti finali di goderci contenuti in streaming o il gaming in rete.</p> <p>L'elenco completo (e costantemente aggiornato) degli episodi è disponibile <a href="https://www.manageddesigns.it/cloud-champions" target="_blank">qui</a>, e <a href="https://www.youtube.com/watch?v=0H--j-fTXnw" target="_blank">stasera</a> partiamo col botto insieme a <strong>Davide Mauri</strong>, senior PM di Azure SQL presso Microsoft Corporation.</p> <p>A vale della live, nella quale sarà possibile interagire con l’ospite mediante la chat, pubblicheremo le registrazioni anche in formato podcast sui seguenti canali:</p> <div style="text-align: center;"> <ul style="list-style-type:none;"> <li style="vertical-align: text-top;"><a style="border-radius: 13px; width: 250px; height: 83px; overflow: hidden; display: inline-block;" href="https://podcasts.apple.com/us/podcast/cloud-champions/id1556383847?itsct=podcast_box&amp;itscg=30200"><img style="border-radius: 13px; width: 250px; height: 83px;" alt="Listen on Apple Podcasts" src="https://tools.applemediaservices.com/api/badges/listen-on-apple-podcasts/badge/it-IT?size=250x83&amp;releaseDate=1614711000&amp;h=a93b54ef105c571457b6e97e6d00f233" /></a></li> <li style="vertical-align: text-top;"><a href="https://www.spreaker.com/show/cloud-champions"><img style="width: 250px; height: 82px;" alt="Ascolta su Spreaker" src="https://www.manageddesigns.it/Content/Uploads/StaticContent/Images/a2e6e93e-d4bc-4b67-b9ca-7f7c578fdc19/Spreaker-button.png" /></a></li> <li style="vertical-align: text-top;"><a href="https://open.spotify.com/show/5gJ14PWEodSHis5nhYrAUs"><img style="width: 250px; height: 102px;" alt="Ascolta su Spotify" src="https://www.manageddesigns.it/Content/Uploads/StaticContent/Images/a2e6e93e-d4bc-4b67-b9ca-7f7c578fdc19/spotify-logo-4.png" /></a></li> </ul> </div><img src="http://blogs.ugidotnet.org/pape/aggbug/102624.aspx" width="1" height="1" />Andrea Saltarellowww.geniodelmale.info è tornato. So long, and thanks for all the fish!http://blogs.ugidotnet.org/geniodelmale/archive/2021/03/01/www-geniodelmale-info-e-tornato-so-long-and-thanks-for.aspxMon, 01 Mar 2021 12:19:31 GMThttp://blogs.ugidotnet.org/geniodelmale/archive/2021/03/01/www-geniodelmale-info-e-tornato-so-long-and-thanks-for.aspxhttp://blogs.ugidotnet.org/geniodelmale/comments/102623.aspxhttp://blogs.ugidotnet.org/geniodelmale/comments/commentRss/102623.aspxhttp://blogs.ugidotnet.org/geniodelmale/archive/2021/03/01/www-geniodelmale-info-e-tornato-so-long-and-thanks-for.aspx#comment0http://blogs.ugidotnet.org/geniodelmale/services/trackbacks/102623.aspxwww.geniodelmale.info è tornato. So long, and thanks for all the fish!Il momento è arrivato. Dopo tanti anni, migliaia di post, migliaia di commenti, ho deciso di rilanciare <a href="https://www.geniodelmale.info">www.geniodelmale.info</a>, di cominciare a bloggare di nuovo in inglese, e di salutare il blog di UgiDotNet, che tanto mi ha dato per la mia crescita personale e professionale.<br /> Un grazie di 💝 ad <a href="https://twitter.com/andysal74">Andrea</a>, per avermi sopportato e, soprattutto, supportato tutti questi anni. <br /> Ho copiato e importato (manualmente) tutti i post che c'erano qui su UgiDotNet, e anche tutti quelli del vecchio blog fatto con Dexter Blog Engine, spero di non aver perso nulla 😊. <br /><br /> Ciao a tutti, spero vogliate seguirmi anche di la.<br /><img src="http://blogs.ugidotnet.org/geniodelmale/aggbug/102623.aspx" width="1" height="1" />Lorenzo BarbieriApp Postepayhttp://blogs.ugidotnet.org/manuel0081/archive/2020/12/15/app-postepay.aspxTue, 15 Dec 2020 13:25:18 GMThttp://blogs.ugidotnet.org/manuel0081/archive/2020/12/15/app-postepay.aspxhttp://blogs.ugidotnet.org/manuel0081/comments/102622.aspxhttp://blogs.ugidotnet.org/manuel0081/comments/commentRss/102622.aspxhttp://blogs.ugidotnet.org/manuel0081/archive/2020/12/15/app-postepay.aspx#comment0http://blogs.ugidotnet.org/manuel0081/services/trackbacks/102622.aspxApp Postepay<div>E' arrivato il momento del Cashback di Stato! <br /> </div> <div>Ma, a parte questo, decido di rispolverare la vecchia Postepay anche per l'euro in più di cashback promesso che, scoprirò, è applicato davvero in pochi negozi e, pertanto, inutile. <br /> </div> <div><br /> </div> <div>Scarico l'app Postepay, configuro la mia carta e... "Servizio temporaneamente non disponibile". <br /> </div> <div>Riprovo nei giorni successivi... nulla. <br /> </div> <div><br /> </div> <div>Provo a telefonare al numero verde dedicato a Postepay e mi perdo nel labirinto delle scelte senza considerare un messaggio di qualche minuto relativo al cashback di Stato che non posso saltare. <br /> </div> <div>Pian piano imparo a memoria le scelte da fare ma ogni volta, a fine percorso, mi viene detto che il centralino è intasato e occorre riprovare più tardi. <br /> </div> <div><br /> </div> <div>Dopo due giorni, riesco a parlare con un operatore e ad aprire un ticket. <br /> </div> <div>Nei giorni successivi sarà impossibile riuscire ad avere informazioni relative a quel ticket. <br /> </div> <div>La cosa più fastidiosa sarà l'assistente digitale: AI pessima. Qualcuno ha mai provato ad usarla? Basta dire "operatore" e lei ti risponderà: "Sei sicuro, non mi vuoi dare un'altra possibilità?" e da lì un giro infinito.<br /> </div> <div><br /> </div> <div>Dalla pagina dell'app scrivo una pessima recensione e mi viene risposto di scrivere il problema alla mail dello sviluppatore. Fatto. <br /> </div> <div>Premetto che l'app era aggiornata all'ultima versione e ho provato anche ad eliminarla e reinstallarla. Alla fine, tramite la pagina Facebook di Postepay mi viene detto di creare il PosteId per usufruire dei servizi online. Lo creo anche se dopo scoprirò che questa notizia era del tutto falsa. <br /> </div> <div><br /> </div> <div>Anche su Facebook, tramite messaggio privato, non ottengo risposta. <br /> </div> <div>Mi sembra abbastanza grave non avere assistenza per un prodotto finanziario (scadente): potrei capire se si trattasse della tessera del supermercato! <br /> </div> <div><br /> </div> <div>Alla fine ricevo una chiamata da un tecnico dopo una settimana di mancato utilizzo dell'app che risolve il problema dicendo che il numero di telefono associato al mio account (fin dall'iscrizione anni fa) era associato anche ad un altro account (creato anni fa). Non potevo disassociarlo in autonomia ma avrei comunque dovuto chiamare loro (che non rispondevano). Ovviamente è caduta la linea mentre verificavo la risoluzione del problema con il tecnico al telefono e non sono stato richiamato. <br /> </div> <div><br /> </div> <div>Direi molte cose da rivedere in questa gestione. <br /> </div> <div>Sicuramente "Servizio temporaneamente non disponibile" non è un messaggio accettabile quando i problemi sono altri!</div><img src="http://blogs.ugidotnet.org/manuel0081/aggbug/102622.aspx" width="1" height="1" />Emanuele PratoMerp incluso nel GitHub Archive Programhttp://blogs.ugidotnet.org/pape/archive/2020/07/29/merp-incluso-nel-github-archive-program.aspxWed, 29 Jul 2020 15:02:52 GMThttp://blogs.ugidotnet.org/pape/archive/2020/07/29/merp-incluso-nel-github-archive-program.aspxhttp://blogs.ugidotnet.org/pape/comments/102621.aspxhttp://blogs.ugidotnet.org/pape/comments/commentRss/102621.aspxhttp://blogs.ugidotnet.org/pape/archive/2020/07/29/merp-incluso-nel-github-archive-program.aspx#comment0http://blogs.ugidotnet.org/pape/services/trackbacks/102621.aspxMerp incluso nel GitHub Archive Program<p>Da qualche anno, nel tempo "libero", sviluppo <a href="https://github.com/mastreeno/merp" target="_blank"><strong>Merp</strong></a>, una applicazione open source che scelsi di creare per dotare la seconda edizione del mio libro <strong><a href="https://www.amazon.com/Microsoft-NET-Architecting-Applications-Enterprise/dp/0735685355/" target="_blank">"Microsoft .NET: Architecting Applications for the Enterprise"</a></strong> di un esempio vero di DDD/CQRS/ES invece dei soliti "snippettini".</p> <p>Nel tempo, Merp ha suscitato un po' di interesse e i suoi 115 fork e 347 star lo hanno portato ad essere incluso nel <a href="https://archiveprogram.github.com/" target="_blank">"GitHub Archive Program"</a>per, testuali parole, essere <em>"preservato per le future generazioni"</em>  insieme a mostri sacri quali <strong>.NET Core, Angular, Hadoop, NodeJS, Rails</strong> ed altri ancora.</p> <p><strong>Speriamo abbiano scelto un commit decente: 1000 anni di insulti e sfottò nuocerebbero ulteriormente alla mia sindrome dell'impostore.</strong></p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/pape/Open-Live-Writer/Merp-inlcuso-nel-GitHub-Archive-Program_1099A/2020%20GitHub%20Archive%20Program_2.png" rel="lightbox"><img title="2020 GitHub Archive Program" style="border: 0px currentcolor; border-image: none; display: inline; background-image: none;" border="0" alt="2020 GitHub Archive Program" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/pape/Open-Live-Writer/Merp-inlcuso-nel-GitHub-Archive-Program_1099A/2020%20GitHub%20Archive%20Program_thumb.png" width="168" height="240" /></a></p><img src="http://blogs.ugidotnet.org/pape/aggbug/102621.aspx" width="1" height="1" />Andrea SaltarelloCi vediamo questa sera alla sessione italiana di Build?http://blogs.ugidotnet.org/geniodelmale/archive/2020/05/20/ci-vediamo-questa-sera-alla-sessione-italiana-di-build.aspxWed, 20 May 2020 10:44:38 GMThttp://blogs.ugidotnet.org/geniodelmale/archive/2020/05/20/ci-vediamo-questa-sera-alla-sessione-italiana-di-build.aspxhttp://blogs.ugidotnet.org/geniodelmale/comments/102620.aspxhttp://blogs.ugidotnet.org/geniodelmale/comments/commentRss/102620.aspxhttp://blogs.ugidotnet.org/geniodelmale/archive/2020/05/20/ci-vediamo-questa-sera-alla-sessione-italiana-di-build.aspx#comment0http://blogs.ugidotnet.org/geniodelmale/services/trackbacks/102620.aspxCi vediamo questa sera alla sessione italiana di Build?<p><img style="margin: 0px 5px 0px 0px; float: left; display: inline;" src="https://external.fmxp3-1.fna.fbcdn.net/safe_image.php?d=AQDdJL57bS_YDtZI&amp;w=476&amp;h=249&amp;url=https%3A%2F%2Fmybuild.azureedge.net%2Fimages%2FMSFT_Build_Homepage_Social_600x335.jpg&amp;cfs=1&amp;upscale=1&amp;fallback=news_d_placeholder_publisher&amp;_nc_hash=AQA-ZZsdijYfiLa0" align="left" />Questa sera sarò in compagnia di un po’ di amici alla sessione italiana di Build, potete iscrivervi qui: <a href="https://mybuild.microsoft.com/sessions/ebfcb753-c90c-4743-931d-c0f84b303543?source=sessions">https://mybuild.microsoft.com/sessions/ebfcb753-c90c-4743-931d-c0f84b303543?source=sessions</a></p> <p>Vedremo vari aspetti legati alle community, io in particolare parlerò di diversità ed inclusione.</p> <p>La mia parte sarà intorno alle 18.30, ci vediamo tra poco!</p><img src="http://blogs.ugidotnet.org/geniodelmale/aggbug/102620.aspx" width="1" height="1" />Lorenzo BarbieriLightning talk a Microsoft Buildhttp://blogs.ugidotnet.org/pape/archive/2020/05/20/lightning-talk-a-microsoft-build.aspxWed, 20 May 2020 07:23:49 GMThttp://blogs.ugidotnet.org/pape/archive/2020/05/20/lightning-talk-a-microsoft-build.aspxhttp://blogs.ugidotnet.org/pape/comments/102619.aspxhttp://blogs.ugidotnet.org/pape/comments/commentRss/102619.aspxhttp://blogs.ugidotnet.org/pape/archive/2020/05/20/lightning-talk-a-microsoft-build.aspx#comment0http://blogs.ugidotnet.org/pape/services/trackbacks/102619.aspxLightning talk a Microsoft Build<p>Prima che scoppiasse la pandemia, l'ultimo evento "fisico" al quale ho partecipato come speaker è stato il <strong>Microsoft Ignite The Tour</strong>: 2 talk, dei quali uno tecnico e l'altro, a me molto più caro, dedicato alla tecnologia quale strumento di inclusione.</p> <p>Quando mi è stato proposto di tornare sul tema, oltretutto a <strong>Microsoft Build</strong>, ho accettato al volo: ne parlerò quindi stasera verso le 18:30 con un <em>lightning talk</em> all'interno dello slot <strong>"Supporting the (other) communities"</strong>.</p> <p>Ci vediamo <a href="https://mybuild.microsoft.com/sessions/ebfcb753-c90c-4743-931d-c0f84b303543">qui</a>. <br /> <br /><a href="https://mybuild.microsoft.com/sessions/ebfcb753-c90c-4743-931d-c0f84b303543"><img title="Logo Microsoft Build 2020" alt="Logo Microsoft Build 2020" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/pape/Open-Live-Writer/5bf7cc87f114_9E97/0%20(1)_1.png" /></a></p> <p>#MicrosoftBuild #a11yDays #inclusione #accessibility</p><img src="http://blogs.ugidotnet.org/pape/aggbug/102619.aspx" width="1" height="1" />Andrea SaltarelloCronache di AWS: prospettiva .NETvskihttp://blogs.ugidotnet.org/pape/archive/2020/05/05/Cronache-di-AWS-prospettiva-NETvski.aspxTue, 05 May 2020 11:27:47 GMThttp://blogs.ugidotnet.org/pape/archive/2020/05/05/Cronache-di-AWS-prospettiva-NETvski.aspxhttp://blogs.ugidotnet.org/pape/comments/102618.aspxhttp://blogs.ugidotnet.org/pape/comments/commentRss/102618.aspxhttp://blogs.ugidotnet.org/pape/archive/2020/05/05/Cronache-di-AWS-prospettiva-NETvski.aspx#comment0http://blogs.ugidotnet.org/pape/services/trackbacks/102618.aspxCronache di AWS: prospettiva .NETvski<p>Non tutto il lock-down vien per nuocere: approfittando della logistica favorevole, del tempo risparmiato non dovendo fare avanti e indietro tra casa/ufficio/clienti e non volendo dedicare la totalità del tempo libero al <em>binge watching</em>, ho finalmente deciso di dedicarmi in modo organizzato ad un tema che avevo nel backlog da un po’: un bell’approfondimento dei miei skill <strong>AWS</strong>.</p> <p>Per rendere quanto più <em>real world</em> possibile il mio approfondimento, mi sono dato un obbiettivo pratico da affiancare alle attività didattiche: prendere <strong><a href="https://github.com/mastreeno/merp">Merp</a></strong> e farlo girare su AWS; ciò, principalmente, per due motivi; il primo è che il progetto usa una serie significativa di componenti (server web, coda di messaggi, SQL Server, MongoDB, …) e, quindi, pubblicarlo comporta dover toccare una gamma abbastanza ampia di servizi quali, ad esempio: </p> <ul> <li><strong>RDS for SQL Server</strong> per i read model</li> <li><strong>Amazon DocumentDB</strong> per gli event store che on-premises sarebbero ospitati da <strong>MongoDB</strong></li> <li><strong>EC2</strong> per vari motivi (SSH, compute, …)</li> <li><strong>AmazonSQS</strong> come trasporto per <strong>Rebus</strong></li> <li><strong>Beanstalk</strong> per le applicazioni web e <strong>Lamba</strong> per endpoint HTTP</li> </ul> <p>Il secondo motivo è che, disponendo di un progetto reale, ho potuto impostare un percorso di <em>application modernization</em> composto da step successivi che, partendo dal solito <em>lift&amp;shift</em>, mi portassero, per così dire, per “aspera a PaaS”.</p> <p>Ne è nata una esperienza, ancora in corso, piena sia di momenti “?” sia di momenti “a-ah!” ed ho pensato di documentarla in una serie di contenuti che pubblicherò su <strong>UGIdotNET</strong>, e composta da articoli che documenteranno il percorso del progetto (es: definizione di un <em>environment</em> <strong>ASP .NET Core</strong> per il supporto ad AWS) e tip che, invece, saranno dedicati a necessità puntali (es: come faccio a connettermi con il mio client MongoDB al cluster DocumentDB?).</p> <p>Il primo è <a href="https://www.ugidotnet.org/tip/1876/Connessione-ad-Amazon-DocumentDB-dall-esterno-di-un-VPC-AWS">qui</a>: chiunque voglia seguire il percorso potrà forkare Merp e smanettare (il progetto è sotto licenza AGPL 3) in prima persona.</p> <p>Proverò anche, parallelamente ad articoli e tip, a postare sul blog per una serie di considerazioni più individuali che al progetto in sè puntando a condividere, ad esempio, risorse utili trovate durante il percorso: tool, pubblicazioni, webinar, tutto quanto mi sia sembrato utile e non sia direttamente contenuto nelle mie pubblicazioni.</p> <p>Proprio relativamente ai webinar, ne segnalo <a href="https://pages.awscloud.com/EMEA-event-OE-windows-tech-webinars-2020-reg-event.html?sc_channel=em&amp;sc_campaign=EMEA_field_WEBINAR_windows-business-webinars_20200506_operational-program&amp;sc_medium=em_&amp;sc_content=SL_webinar_field&amp;sc_geo=emea&amp;sc_country=mult&amp;sc_outcome=sl&amp;trkCampaign=emea_fy20_gc500_windows&amp;trk=em_salesinv">un paio</a> che seguirò prossimamente: soprattutto <strong>“Serverless and Container .NET Best Practices”</strong> mi torna particolarmente utile.</p><img src="http://blogs.ugidotnet.org/pape/aggbug/102618.aspx" width="1" height="1" />Andrea SaltarelloSummer 2019 reading & watching listhttp://blogs.ugidotnet.org/luKa/archive/2019/08/03/Summer-2019-reading-watching-list.aspxSat, 03 Aug 2019 16:08:23 GMThttp://blogs.ugidotnet.org/luKa/archive/2019/08/03/Summer-2019-reading-watching-list.aspxhttp://blogs.ugidotnet.org/luKa/comments/102617.aspxhttp://blogs.ugidotnet.org/luKa/comments/commentRss/102617.aspxhttp://blogs.ugidotnet.org/luKa/archive/2019/08/03/Summer-2019-reading-watching-list.aspx#comment0http://blogs.ugidotnet.org/luKa/services/trackbacks/102617.aspxSummer 2019 reading & watching list<div>Ecco una selezione di post e video per l'estate :-)<br /> </div> <div><br /> </div> <div><br /> </div> <div><span style="font-weight: bold;">Agile &amp; Agility</span> </div> <div><br /> </div> <div>- L'essenza del Agile e della Agility: <a href="http://www.smharter.com/blog/2019/05/29/the-three-pillars-of-agile/">http://www.smharter.com/blog/2019/05/29/the-three-pillars-of-agile/</a></div> <div><br /> </div> <div>- Teorie e modelli utili al Agile: <a href="https://www.linkedin.com/pulse/manoeuvre-agility-meta-agility-only-complexity-geeks-luca-minudel/">https://www.linkedin.com/pulse/manoeuvre-agility-meta-agility-only-complexity-geeks-luca-minudel/</a></div> <div><br /> </div> <div>-  Un aggiornamento al linguaggio datato del Manifesto Agile (utile solo per Training, non è una evoluzione del manifesto ... un altro post su questo tema stà per arrivare): <a href="http://www.smharter.com/blog/2019/06/12/freshened-up-agile-manifesto/">http://www.smharter.com/blog/2019/06/12/freshened-up-agile-manifesto/</a></div> <div><br /> </div> <div><br /> </div> <div> <div><span style="font-weight: bold;">Fraintendimenti e incomprensioni del Agile</span></div> <div><br /> </div> - SAFe il framework che più e più esperti sconsigliano: <a href="https://www.linkedin.com/pulse/safe-lean-agile-modern-management-theory-luca-minudel/">https://www.linkedin.com/pulse/safe-lean-agile-modern-management-theory-luca-minudel/</a><br /> </div> <div><br /> </div> <div>- Figuracce delle grandi aziende di consulenza che si improvvisano esperte di Agile: <a href="https://www.linkedin.com/posts/lucaminudel_misunderstoodagile-misappliedagile-missoldagile-activity-6564484028391583744-1yKP">https://www.linkedin.com/posts/lucaminudel_misunderstoodagile-misappliedagile-missoldagile-activity-6564484028391583744-1yKP</a><br /> </div> <div><br /> </div> <div>- Ossessione per le metriche: <a href="https://www.linkedin.com/pulse/metrics-obsession-lean-agile-bean-counters-luca-minudel/">https://www.linkedin.com/pulse/metrics-obsession-lean-agile-bean-counters-luca-minudel/</a></div> <div><br /> </div> <div><br /> </div> <div> <span style="font-weight: bold;">Libro</span> </div> <div> <div> <div><br /> </div> - Enterprise Agility: Being Agile in a Changing World by Sunil Mundra (ThoughtWorks): <a href="https://www.amazon.co.uk/Enterprise-Agility-Being-Agile-Changing/dp/1788990641">https://www.amazon.co.uk/Enterprise-Agility-Being-Agile-Changing/dp/1788990641</a><br /> </div> <div><br /> </div> <div><br /> </div> <div> <div> <div><span style="font-weight: bold;"><span style="font-weight: bold;">Video</span> </span></div> <div><br /> </div> - How F1 teams crack technical debt <a href="https://youtu.be/4C2hOC0WbcA">https://youtu.be/4C2hOC0WbcA</a></div> <div><br /> </div> <div>- Cultural Change: Startups wish they were bigger, big companies dream of being Startup-ish. So what? <a href="https://youtu.be/Ue2XXWOulM0">https://youtu.be/Ue2XXWOulM0<br /> </a></div> <div><br /> </div> <div><br /> </div> <div><br /> </div> <div><br /> </div> </div> <div><br /> </div> </div> <div><br /> </div><img src="http://blogs.ugidotnet.org/luKa/aggbug/102617.aspx" width="1" height="1" />Luca MinudelBenvenuto Surface Book 2http://blogs.ugidotnet.org/geniodelmale/archive/2019/01/31/Benvenuto-Surface-Book-2.aspxWed, 30 Jan 2019 23:05:40 GMThttp://blogs.ugidotnet.org/geniodelmale/archive/2019/01/31/Benvenuto-Surface-Book-2.aspxhttp://blogs.ugidotnet.org/geniodelmale/comments/102615.aspxhttp://blogs.ugidotnet.org/geniodelmale/comments/commentRss/102615.aspxhttp://blogs.ugidotnet.org/geniodelmale/archive/2019/01/31/Benvenuto-Surface-Book-2.aspx#comment0http://blogs.ugidotnet.org/geniodelmale/services/trackbacks/102615.aspxBenvenuto Surface Book 2<p>Da qualche giorno sto “giocando” col mio nuovo Surface Book 2, devo dire che mi trovo veramente bene.</p> <p>Certo, un paio di cose non mi hanno convinto, e magari in un secondo momento farò un post per parlarne, ma l’esperienza è ottima. Erano anni che usavo un form factor diverso, quello del Surface Pro, dal mitico #1 comprato da un collega perché ancora non si trovava in Italia, al Pro 2, comprato il giorno di lancio negli US assieme alla Docking Station INTROVABILE, al Pro 3, il vero salto di qualità. Tutti questi me li ero comprati io, lasciando il PC aziendale a casa. Dovevo avere un Surface Pro.</p> <p>Poi è arrivato il Pro 4 di mamma Microsoft, che mi ha accompagnato negli ultimi tre anni con grandi successi, ma avendo quasi terminato la batteria. Per fortuna avevo comprato il “mega power bank” di Li-zone, una bomba.</p> <p>Ora si riparte, con un PC molto più potente, un po’ più pesante, con uno schermo che mi piace molto.</p><img src="http://blogs.ugidotnet.org/geniodelmale/aggbug/102615.aspx" width="1" height="1" />Lorenzo BarbieriIn giro: prossimi eventi [UPDATED]http://blogs.ugidotnet.org/pape/archive/2019/01/28/In-giro-prossimi-eventi.aspxMon, 28 Jan 2019 16:02:31 GMThttp://blogs.ugidotnet.org/pape/archive/2019/01/28/In-giro-prossimi-eventi.aspxhttp://blogs.ugidotnet.org/pape/comments/102614.aspxhttp://blogs.ugidotnet.org/pape/comments/commentRss/102614.aspxhttp://blogs.ugidotnet.org/pape/archive/2019/01/28/In-giro-prossimi-eventi.aspx#comment0http://blogs.ugidotnet.org/pape/services/trackbacks/102614.aspxIn giro: prossimi eventi [UPDATED]<div> Ispirato da <a href="http://blogs.ugidotnet.org/geniodelmale/archive/2019/01/23/Prossimi-eventi-dove-incontrarci.aspx">Lorenzo</a>, ho deciso di iniziare a pubblicare sul blog gli eventi nei quali sarò presente: </div> <div> <ul> <li>Il 31 gennaio sarò presente, in qualità di speaker, alla <a href="https://www.microsoft.com/it-it/ignite-the-tour/milan">tappa milanese del <strong>Microsoft Ignite Tour</strong></a>; nello specifico, terrò  la sessione <strong>"Azure tales: real world Event Sourcing"</strong> (codice BRK3589) alle 9:30 nella sala "Amber 7" e, con gli amici (in rigoroso ordine alfabetico) Daniele, Laurent e Martina sarò uno dei sedicenti esperti protagonisti dell'<em>Ask The Expert</em><strong> "Here's how the cloud will solve all your problems"</strong> (codice THR2506) alle 17:10 nel Theater 2</li> <li>Sempre il 31 gennaio, ma IMHO merita un punto a parte, insieme ad <a href="http://blogs.ugidotnet.org/compass/default.aspx">Enos</a> terrò alle 10:50 la sessione <strong>“Implementing bots and Alexa skills with Azure Cognitive Services and the Microsoft Bot Framework”</strong> nel meetup organizzato da <strong><a href="http://www.ugidotnet.org">UGIdotNET</a></strong> presso il <strong>Microsoft Ignite Tour</strong></li> <li>L'1 febbraio parteciperò <a href="https://www.meetup.com/it-IT/Azure-Meetup-Milano/events/258288582/">all'evento <strong>"Ignite your Azure"</strong></a>, il primo incontro organizzato dal neonato <strong>Azure Meetup Milano</strong></li> <li>il 7 febbraio, presso la Microsoft House, sarò speaker presso <a href="http://goo.gl/iwBUFx">l’evento<strong> “Azure Experience: migrare le tue applicazioni? E’ possibile!”</strong></a> durante il quale terrò due sessioni dedicate, rispettivamente, ai pattern ricorrenti nella migrazione di applicazioni verso Azure ed ad illustrare alcune delle opportunità abilitate dalla adozione del cloud a valle della migrazione. L’intenzione, per intenderci, consiste nello sfatare un po’ dei miti per i quali “migrare in cloud la mia applicazione? Impossibile, perché bla bla bla bla, …”</li> </ul> </div> <p>L’invito è sempre il solito: se ci sarete ed avete voglia di fare 2 chiacchiere, non esitate a farvi avanti.</p><img src="http://blogs.ugidotnet.org/pape/aggbug/102614.aspx" width="1" height="1" />Andrea SaltarelloProssimi eventi dove incontrarcihttp://blogs.ugidotnet.org/geniodelmale/archive/2019/01/23/Prossimi-eventi-dove-incontrarci.aspxWed, 23 Jan 2019 09:47:24 GMThttp://blogs.ugidotnet.org/geniodelmale/archive/2019/01/23/Prossimi-eventi-dove-incontrarci.aspxhttp://blogs.ugidotnet.org/geniodelmale/comments/102613.aspxhttp://blogs.ugidotnet.org/geniodelmale/comments/commentRss/102613.aspxhttp://blogs.ugidotnet.org/geniodelmale/archive/2019/01/23/Prossimi-eventi-dove-incontrarci.aspx#comment0http://blogs.ugidotnet.org/geniodelmale/services/trackbacks/102613.aspxProssimi eventi dove incontrarci<p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/geniodelmale/Open-Live-Writer/Prossimi-eventi-dove-incontrarci_8794/lorenzo_600x600_2.jpg"><img title="lorenzo_600x600" style="margin: 5px 5px 0px 0px; float: left; display: inline; background-image: none;" border="0" alt="lorenzo_600x600" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/geniodelmale/Open-Live-Writer/Prossimi-eventi-dove-incontrarci_8794/lorenzo_600x600_thumb.jpg" width="244" align="left" height="244" /></a>Ogni tanto aggiorno il blog con i prossimi eventi dove possiamo incontrarci, e rieccoci con i primi eventi (in Italia) di questo semestre:</p> <p>- 31 gennaio e 1 febbraio, <a href="https://www.microsoft.com/it-it/ignite-the-tour/milan"><strong>Microsoft Ignite Tour</strong></a>, al 90% sarò presente almeno uno dei due giorni come partecipante.</p> <p>- sabato 2 marzo,<a href="https://www.eventbrite.com/e/global-diversity-cfp-day-italian-edition-workshop-tickets-7349116405"><strong>global diversity CFP day</strong></a>, assieme a Mauro Servienti abbiamo organizzato un evento dedicato ad aspiranti speaker o a persone che vogliano migliorarsi, in un ambiente inclusivo e accogliente, indipendentemente dal tipo di talk, dal fatto che la persona appartenga o meno ad una minoranza, insomma, un posto PROTETTO dove farsi le ossa. Ci saranno due sessioni e poi chi vorrà potrà mettersi alla prova.</p> <p>L’elenco completo con gli eventi anche fuori dall’Italia lo trovate <a href="https://www.linkedin.com/pulse/where-meet-me-2019-h1-edition-lorenzo-barbieri/" target="_blank">qui</a>.</p><img src="http://blogs.ugidotnet.org/geniodelmale/aggbug/102613.aspx" width="1" height="1" />Lorenzo BarbieriRitorno al futurohttp://blogs.ugidotnet.org/ABS/archive/2018/11/05/Ritorno-al-futuro.aspxMon, 05 Nov 2018 17:20:40 GMThttp://blogs.ugidotnet.org/ABS/archive/2018/11/05/Ritorno-al-futuro.aspxhttp://blogs.ugidotnet.org/ABS/comments/102612.aspxhttp://blogs.ugidotnet.org/ABS/comments/commentRss/102612.aspxhttp://blogs.ugidotnet.org/ABS/archive/2018/11/05/Ritorno-al-futuro.aspx#comment0http://blogs.ugidotnet.org/ABS/services/trackbacks/102612.aspxRitorno al futuroIl mio primo post su UGI e' di Ottobre 2003, l'ultimo di Luglio 2009....<br /> <br /> Il primo corrisponde piu' o meno al periodo in cui fui invitato da <a href="http://blogs.ugidotnet.org/pape/default.aspx" target="_blank">Andrea</a> a parlare di Agile ad un evento (chi c'era? era il <a href="https://www.ugidotnet.org/eventi/10/Agile" target="_blank">17 Settembre 2003</a>!).<br /> <br /> L'ultimo piu' o meno a quando, ormai da 4 anni a Londra, stare dietro alle attivita' anche in Italia era diventato difficile e infatti e' lo stesso anno in cui cominciai a pensare di fare un passo indietro anche nell'organizzazione dell'Italian Agile Day.<br /> <br /> Sono passati 9 anni da allora e sono di nuovo qui :-)<br /> <br /> L'idea originale era di aprire una filiale Italiana della <a href="https://highops.com/" target="_blank">mia azienda UK</a> ma, come si dice, la vita segue spesso percorsi misteriosi e mi ritrovo ora in <a href="https://www.manageddesigns.it/" target="_blank">Managed Designs</a>, socio oltre che amico di quello stesso Andrea che mi invito' a parlare ad un evento UGI 15 anni fa :-D<br /> <br /> La cosa ha riportato alla mente parecchi eventi UGI memorabili ma per me quello che resta una spanna sopra gli altri rimane l'evento al <a href="https://www.ugidotnet.org/eventi/36/Web-Development" target="_blank">cinema Arcadia con Andrea e Fabio vestiti da Spiderman nel 2004</a>. Peccato non trovare le foto ma sono certo qualcuno qui le abbia da qualche parte...<br /> <br /> Spero di avere l'occasione di rivedere di persona tanti vecchi amici, possibilmente al prossimo evento UGI ;-)<img src="http://blogs.ugidotnet.org/ABS/aggbug/102612.aspx" width="1" height="1" />Marco Abis