Wednesday, March 26, 2025

Hybrid Connections WebSockets in Azure Relay

Hybrid Connections WebSockets in Azure Relay

Source: https://learn.microsoft.com/en-us/azure/azure-relay/relay-hybrid-connections-dotnet-get-started

1. Create a Namespace





Get Managed credentials 

Create Hybrid Connection 


2. Create a server application (listener)

using Microsoft.Azure.Relay;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace myserver
{
    public class Program
    {
        private const string RelayNamespace = "sreerelay.servicebus.windows.net";
        private const string ConnectionName = "sreehybridconn";
        private const string KeyName = "RootManageSharedAccessKey";
        private const string Key = "Wtcg6qDIGI4aFts+qYH+zmHwCL1Q=";

        public static void Main(string[] args)
        {
            RunAsync().GetAwaiter().GetResult();
        }

        private static async Task RunAsync()
        {
            var cts = new CancellationTokenSource();
            var tokenProvider =
            TokenProvider.CreateSharedAccessSignatureTokenProvider(KeyName, Key);
            var listener = new HybridConnectionListener(new Uri(string.Format(
            "sb://{0}/{1}", RelayNamespace, ConnectionName)), tokenProvider);
            listener.Connecting += (o, e) => { Console.WriteLine("Connecting"); };
            listener.Offline += (o, e) => { Console.WriteLine("Offline"); };
            listener.Online += (o, e) => { Console.WriteLine("Online"); };
            await listener.OpenAsync(cts.Token);
            Console.WriteLine("Server listening");
            cts.Token.Register(() => listener.CloseAsync(CancellationToken.None));
            new Task(() => Console.In.ReadLineAsync().ContinueWith((s) => {
            cts.Cancel(); })).Start();
            while (true)
            {
                var relayConnection = await listener.AcceptConnectionAsync();
                if (relayConnection == null)
                {
                    break;
                }
                ProcessMessagesOnConnection(relayConnection, cts);
            }
            await listener.CloseAsync(cts.Token);
        }

        private static async void ProcessMessagesOnConnection(HybridConnectionStream
        relayConnection, CancellationTokenSource cts)
        {
            Console.WriteLine("New session");
            var reader = new StreamReader(relayConnection);
            var writer = new StreamWriter(relayConnection) { AutoFlush = true };
            while (!cts.IsCancellationRequested)
            {
                try
                {
                    var line = await reader.ReadLineAsync();
                    if (string.IsNullOrEmpty(line))
                    {
                        await relayConnection.ShutdownAsync(cts.Token);
                        break;
                    }
                    Console.WriteLine(line);
                    await writer.WriteLineAsync($"Echo: {line}");
                }
                catch (IOException)
                {
                    Console.WriteLine("Client closed connection");
                    break;
                }
            }
            Console.WriteLine("End session");
            await relayConnection.CloseAsync(cts.Token);
        }
    }
}


3. Create a client application (sender)

using Microsoft.Azure.Relay;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace myclient
{
    class Program
    {
        private const string RelayNamespace = "sreerelay.servicebus.windows.net";
        private const string ConnectionName = "sreehybridconn";
        private const string KeyName = "RootManageSharedAccessKey";
        private const string Key = "Wtcg6qDIGI4aFts+qYH+zmHwCL1Q=";

        static void Main(string[] args)
        {
            RunAsync().GetAwaiter().GetResult();
        }

        private static async Task RunAsync()
        {
            Console.WriteLine("Enter lines of text to send to the server with ENTER");
            var tokenProvider =
            TokenProvider.CreateSharedAccessSignatureTokenProvider(KeyName, Key);
            var client = new HybridConnectionClient(new Uri(String.Format(
            "sb://{0}/{1}", RelayNamespace, ConnectionName)), tokenProvider);
            var relayConnection = await client.CreateConnectionAsync();

            var reads = Task.Run(async () =>
            {
                var reader = new StreamReader(relayConnection);
                var writer = Console.Out;
                do
                {
                    string line = await reader.ReadLineAsync();
                    if (String.IsNullOrEmpty(line))
                        break;
                    await writer.WriteLineAsync(line);
                }
                while (true);
            });

            var writes = Task.Run(async () =>
            {
                var reader = Console.In;
                var writer = new StreamWriter(relayConnection) { AutoFlush = true };
                do
                {
                    string line = await reader.ReadLineAsync();
                    await writer.WriteLineAsync(line);
                    if (String.IsNullOrEmpty(line))
                        break;
                }
                while (true);
            });
           
            await Task.WhenAll(reads, writes);
            await relayConnection.CloseAsync(CancellationToken.None);
        }
    }
}


OutPut:


Monday, March 10, 2025

Actionable Email Developer Dashboard

 Actionable Email Developer Dashboard:

Source:
Get started with actionable messages in Office 365: https://learn.microsoft.com/en-us/outlook/actionable-messages/get-started

Register your service with the actionable email developer dashboard: https://learn.microsoft.com/en-us/outlook/actionable-messages/email-dev-dashboard

1. Create Provider in ''Actionable Email Developer Dashboard - https://outlook.office.com/connectors/oam/publish "

2. Save "Provider Id (originator)" in notepad.

3. Approve submitted provider here: https://outlook.office.com/connectors/oam/admin





4. Prepare Json as below: 

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <script type="application/adaptivecard+json">{
    "type": "AdaptiveCard",
    "version": "1.0",
    "hideOriginalBody": true,
    "originator": "Provider Id (originator) : GUID from Previous step",
    "body": [
      {
        "type": "TextBlock",
        "text": "Visit the Outlook Dev Portal",
        "size": "large"
      },
      {
        "type": "TextBlock",
        "text": "Click **Learn More** to learn more about Actionable Messages!"
      },
      {
        "type": "Input.Text",
        "id": "feedbackText",
        "placeholder": "Let us know what you think about Actionable Messages"
      }
    ],
    "actions": [
      {
        "type": "Action.Http",
        "title": "Send Feedback",
        "method": "POST",
        "url": "https://...",
        "body": "{{feedbackText.value}}"
      },
      {
        "type": "Action.OpenUrl",
        "title": "Learn More",
        "url": "https://learn.microsoft.com/outlook/actionable-messages"
      }
    ]
  }
  </script>
</head>
<body>
Visit the <a href="https://learn.microsoft.com/outlook/actionable-messages">Outlook Dev Portal</a> to learn more about Actionable Messages.
</body>
</html>

C# Code:
using Azure.Identity;
using Microsoft.Graph;
using Microsoft.Graph.Models;
using Microsoft.Graph.Users.Item.SendMail;

public class Program
{
    public static async Task Main(string[] args)
    {
        var clientId = "6e4110e7-e5b0d411db60";
        var tenantId = "bb55f134-82bf54373c6d";
        var clientSecret = "imx8Q~Q~AHcGN";
        var userFromEmail = "user1@test.onmicrosoft.com";
        var userToEmails = "user2@test.onmicrosoft.com,user3@test.onmicrosoft.com";

        var credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
        var graphClient = new GraphServiceClient(credential);

        string adaptiveCardJson = @"<html>
        <head>
          <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
          <script type='application/adaptivecard+json'>{
            'type': 'AdaptiveCard',
            'version': '1.0',
            'hideOriginalBody': true,
            'originator': 'a115aabe-03994fbaf1d',
            'body': [
              {
                'type': 'TextBlock',
                'text': 'Visit the Outlook Dev Portal',
                'size': 'large'
              },
              {
                'type': 'TextBlock',
                'text': 'Click **Learn More** to learn more about Actionable Messages!'
              },
              {
                'type': 'Input.Text',
                'id': 'feedbackText',
                'placeholder': 'Let us know what you think about Actionable Messages'
              }
            ],
            'actions': [
              {
                'type': 'Action.Http',
                'title': 'Send Feedback',
                'method': 'POST',
                'url': 'https://...',
                'body': '{{feedbackText.value}}'
              },
              {
                'type': 'Action.OpenUrl',
                'title': 'Learn More',
                'url': 'https://learn.microsoft.com/outlook/actionable-messages'
              }
            ]
          }
          </script>
        </head>
        <body>
        Visit the <a href='https://learn.microsoft.com/outlook/actionable-messages'>Outlook Dev
        Portal</a> to learn more about Actionable Messages.
        </body>
        </html>";

        List<string> userToEmailList = new List<string>(userToEmails.Split(','));
        var message = new Message
        {
            Subject = "Test Subject",
            Body = new ItemBody
            {
                ContentType = BodyType.Html,
                Content = $"{adaptiveCardJson}"
            },
            ToRecipients = userToEmailList.Select(email => new Recipient { EmailAddress =
            new EmailAddress { Address = email } }).ToList(),
        };
        var sendMailRequest = new SendMailPostRequestBody { Message = message };
        await graphClient.Users[userFromEmail].SendMail.PostAsync(sendMailRequest);

        Console.ReadKey();
    }
}



OutPut:






Monday, March 3, 2025

Connect SharePoint using Azure App Application/Delegate Authentication in C#

1. Connect SharePoint using Azure App Application Authentication in C#
Create Azure app and give below Application permissions. 


using Azure.Identity;
using Microsoft.Graph;

public class Program
{
    public static async Task Main(string[] args)
    {
        string tenantId = "";
        string clientId = "";
        string clientSecret = "";
        string siteId = "283f598a-6b0f-4ba5-af06-c72a0cef8f42";
        string listId = "e9609d64-1f36-45a2-8260-743998ea2cd4";
        var credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
        var graphClient = new GraphServiceClient(credential);
        var items = await graphClient.Sites[siteId].Lists[listId].Items.GetAsync();
        foreach (var item in items.Value)
        {
            Console.WriteLine($"Item ID: {item.Id}, Created By: {item.CreatedBy?.User?.DisplayName}");
        }
        Console.ReadKey();
    }
}



2. Connect SharePoint using Azure App Delegate Authentication in C#

Featured Post

Export a User's Manager Chain and Peers to CSV with Microsoft Graph PowerShell

Ever needed to answer “Who is my manager’s manager, all the way to the top?” or “Who else reports to my manager?” for an audit, an approv...

Popular posts