@manhng

Welcome to my blog!

Exchange 2013

June 22, 2020 14:59

Exchange 2013 (edit)

Exchange 2013 introduced a new affinity model which means that streaming subscriptions to multiple mailboxes need to be handled in a different way to earlier versions.  If you are connecting to a single mailbox, you shouldn’t have a problem, but you most likely will encounter issues if you are connecting to many mailboxes.  Additionally, the EWS managed API has not yet been updated with the changes, so quite a lot of the process needs to be implemented manually.

The steps needed to connect and monitor multiple mailboxes are as follows (please see http://msdn.microsoft.com/en-us/library/office/dn458789(v=exchg.150).aspx ):

  1. Call Autodiscover for each mailbox requesting the ExternalEwsUrl and a new setting called “GroupingInformation” (mailbox1, mailbox2, mailbox3, etc.)
  2. Group the mailboxes by a concatenation of ExternalEwsUrl + GroupingInformation
  3. For each group (with ~ 200 mailboxes each)
    1. Create the ExchangeService object (so any cookie is sent in the following requests
    2. Add a header to this request called “X-AnchorMailbox” with a value set the SMTP address of the first mailbox in the group
    3. Add a header to this request called “X-PreferServerAffinity” with a value set to “true”
  4. Send a Subscribe request for each mailbox in this group to get a SubscriptionId (using ApplicationImpersonation)
  5. Send a GetStreamingEvents request with all the SubscriptionIds from the above step (not using ApplicationImpersonation)
  6. Pass events returned by GetStreamingEvents or GetEvents to a separate thread for processing

I have published a code sample to Codeplex (http://ewsstreaming.codeplex.com/) that implements the above logic using the EWS Managed API.  For further updates, please follow the Codeplex pages – they will be updated as the sample is improved.

EWS Streaming Notification Sample Application

EWS Streaming Notification Sample

This project demonstrates how to handle streaming notifications specifically for Wave 15 of Office 365 (and also Exchange 2013 on-premises installations). The code has recently been rewritten completely to simplify the grouping logic and add some error handling (disconnect events are handled properly, though currently subscription errors are not handled).

https://archive.codeplex.com/?p=ewsstreaming

Sample application demonstrating how to create a daemon application that interacts with EXO using EWS

https://github.com/developermessaging/EWSDaemonOAuthSample

An old code sample illustrating the use of SimpleMAPI

https://github.com/developermessaging/SimpleMAPISample

Azure Cloud

https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Client-Applications

https://docs.microsoft.com/en-us/graph/overview

https://docs.microsoft.com/en-us/graph/whats-new-overview

https://docs.microsoft.com/en-us/graph/security-authorization

https://docs.microsoft.com/en-us/mem/intune/developer/intune-graph-apis

https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-windows-desktop

https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-net-initializing-client-applications

https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-app-registration

Async & Await

The async/await keywords

https://www.ryadel.com/en/asyncutil-c-helper-class-async-method-sync-result-wait/

https://markheath.net/post/async-antipatterns

https://cpratt.co/async-tips-tricks/

ASP.NET Web API + Ajax Sync and Ajax Async

https://www.c-sharpcorner.com/UploadFile/dacca2/web-api-with-ajax-understand-synchronous-and-asynchronous-c/

Secure Password

https://www.sqlshack.com/how-to-secure-your-passwords-with-powershell/

https://www.tutorialspoint.com/explain-secure-password-encryption-with-powershell

Auto Tasks

https://www.howtogeek.com/120011/stupid-geek-tricks-how-to-send-email-from-the-command-line-in-windows-without-extra-software/

https://www.howtogeek.com/125045/how-to-easily-send-emails-from-the-windows-task-scheduler/

https://www.howtogeek.com/408827/how-to-schedule-an-email-in-outlook/

Bulk Insert

July 9, 2018 15:39

Quickly insert millions of rows in SQL Server in .NET (edit)

https://www.softfluent.com/blog/dev/Quickly-insert-millions-of-rows-in-SQL-Server-in-NET

Ghi chú

Sổ chi tiết công nợ của một khách hàng
Sổ cái của một tài khoản
Bảng cân đối phát sinh công nợ của một tài khoản

https://docs.microsoft.com/en-us/aspnet/core/tutorials/index?view=aspnetcore-2.1#how-to-download-a-sample
https://github.com/aspnet/Docs/tree/master/aspnetcore/fundamentals/app-state/samples
https://github.com/aspnet/Docs/tree/master/aspnetcore/fundamentals/app-state/samples/2.x/SessionSample

Bulk Insert
https://chsakell.com/2014/07/13/insert-millions-of-records-in-sql-server-table-at-once/
https://blogs.msdn.microsoft.com/nikhilsi/2008/06/11/bulk-insert-into-sql-from-c-app/
https://www.codeproject.com/Articles/439843/Handling-BULK-Data-insert-from-CSV-to-SQL-Server
https://programmingwithmosh.com/csharp/using-sqlbulkcopy-for-fast-inserts/
https://www.codemag.com/article/1701101/Processing-Large-Datasets-Using-C

ObjectDataReader (BulkInsert)

https://gist.github.com/meziantou/174e2791dec966be837746750b87d069

1) SQL SCRIPT

CREATE TABLE [dbo].[Customer](
	[Id] [uniqueidentifier] NOT NULL,
	[FirstName] [nvarchar](50) NULL,
	[LastName] [nvarchar](50) NULL,
	[DateOfBirth] [datetime2](7) NULL
) ON [PRIMARY]
GO

2) Class Library: ObjectDataReader.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq.Expressions;

namespace DOTNETCoreClassLibrary1
{
    public class ObjectDataReader : DbDataReader
    {
        private IEnumerator _iterator;
        private IDictionary<string, int> _propertyNameToOrdinal = new Dictionary<string, int>();
        private IDictionary<int, string> _ordinalToPropertyName = new Dictionary<int, string>();
        private Func<T, object>[] _getPropertyValueFuncs;

        public ObjectDataReader(IEnumerator items)
        {
            _iterator = items ?? throw new ArgumentNullException(nameof(items));

            Initialize();
        }

        private void Initialize()
        {
            int ordinal = 0;
            var properties = typeof(T).GetProperties();
            _getPropertyValueFuncs = new Func<T, object>[properties.Length];
            foreach (var property in properties)
            {
                string propertyName = property.Name;
                _propertyNameToOrdinal.Add(propertyName, ordinal);
                _ordinalToPropertyName.Add(ordinal, propertyName);

                var parameterExpression = Expression.Parameter(typeof(T), "x");
                var func = (Func<T, object>)Expression.Lambda(Expression.Convert(Expression.Property(parameterExpression, propertyName), typeof(object)), parameterExpression).Compile();
                _getPropertyValueFuncs[ordinal] = func;

                ordinal++;
            }
        }

        public override object this[int ordinal] => GetValue(ordinal);

        public override object this[string name] => GetValue(GetOrdinal(name));

        public override int Depth => 0;

        public override int FieldCount => _ordinalToPropertyName.Count;

        public override bool HasRows => true;

        public override bool IsClosed => _iterator != null;

        public override int RecordsAffected => throw new NotImplementedException();

        public override bool GetBoolean(int ordinal)
        {
            return (bool)GetValue(ordinal);
        }

        public override byte GetByte(int ordinal)
        {
            return (byte)GetValue(ordinal);
        }

        public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length)
        {
            throw new NotImplementedException();
        }

        public override char GetChar(int ordinal)
        {
            return (char)GetValue(ordinal);
        }

        public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length)
        {
            throw new NotImplementedException();
        }

        public override string GetDataTypeName(int ordinal)
        {
            throw new NotImplementedException();
        }

        public override DateTime GetDateTime(int ordinal)
        {
            return (DateTime)GetValue(ordinal);
        }

        public override decimal GetDecimal(int ordinal)
        {
            return (decimal)GetValue(ordinal);
        }

        public override double GetDouble(int ordinal)
        {
            return (double)GetValue(ordinal);
        }

        public override IEnumerator GetEnumerator()
        {
            throw new NotImplementedException();
        }

        public override Type GetFieldType(int ordinal)
        {
            var value = GetValue(ordinal);
            if (value == null)
                return typeof(object);

            return value.GetType();
        }

        public override float GetFloat(int ordinal)
        {
            return (float)GetValue(ordinal);
        }

        public override Guid GetGuid(int ordinal)
        {
            return (Guid)GetValue(ordinal);
        }

        public override short GetInt16(int ordinal)
        {
            return (short)GetValue(ordinal);
        }

        public override int GetInt32(int ordinal)
        {
            return (int)GetValue(ordinal);
        }

        public override long GetInt64(int ordinal)
        {
            return (long)GetValue(ordinal);
        }

        public override string GetName(int ordinal)
        {
            if (_ordinalToPropertyName.TryGetValue(ordinal, out var name))
                return name;

            return null;
        }

        public override int GetOrdinal(string name)
        {
            if (_propertyNameToOrdinal.TryGetValue(name, out var ordinal))
                return ordinal;

            return -1;
        }

        public override string GetString(int ordinal)
        {
            return (string)GetValue(ordinal);
        }

        public override object GetValue(int ordinal)
        {
            var func = _getPropertyValueFuncs[ordinal];
            return func(_iterator.Current);
        }

        public override int GetValues(object[] values)
        {
            int max = Math.Min(values.Length, FieldCount);
            for (var i = 0; i < max; i++)
            {
                values[i] = IsDBNull(i) ? DBNull.Value : GetValue(i);
            }

            return max;
        }

        public override bool IsDBNull(int ordinal)
        {
            return GetValue(ordinal) == null;
        }

        public override bool NextResult()
        {
            return false;
        }

        public override bool Read()
        {
            return _iterator.MoveNext();
        }
    }
}

3) Models: Customer.cs

using System;
using System.Collections.Generic;

namespace DOTNETCoreClassLibrary1
{
    public class Customer
    {
        public Guid Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime DateOfBirth { get; set; }

        public static IEnumerable Generate(int count)
        {
            for (int i = 0; i < count; i++)
            {
                yield return new Customer
                {
                    Id = Guid.NewGuid(),
                    FirstName = "FirstName" + i,
                    LastName = "LastName" + i,
                    DateOfBirth = DateTime.UtcNow
                };
            }
        }

        public static IEnumerable Generate(int start, int count)
        {
            for (int i = start; i < count; i++)
            {
                yield return new Customer
                {
                    Id = Guid.NewGuid(),
                    FirstName = "FirstName" + i,
                    LastName = "LastName" + i,
                    DateOfBirth = DateTime.UtcNow
                };
            }
        }
    }
}

4) Controllers: HomeController.cs

using ASPNETCoreWebApplication1.Models;
using DOTNETCoreClassLibrary1;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using System;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace ASPNETCoreWebApplication1.Controllers
{
    public class HomeController : Controller
    {
        private readonly string _connectionString = "";

        public HomeController(IConfiguration configuration)
        {
            _connectionString = configuration.GetConnectionString("DefaultConnection");
        }

        public async Task Index()
        {
            await InsertAsync();

            return View();
        }

        private async Task InsertAsync(CancellationToken ct = default(CancellationToken))
        {
            using (var connection = new SqlConnection(this._connectionString))
            {
                await connection.OpenAsync(ct);
                using (var bulk = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, null))
                {
                    var customers = Customer.Generate(1000000);
                    using (var enumerator = customers.GetEnumerator())
                    using (var customerReader = new ObjectDataReader(enumerator))
                    {
                        bulk.DestinationTableName = "Customer";
                        bulk.ColumnMappings.Add(nameof(Customer.Id), "Id");
                        bulk.ColumnMappings.Add(nameof(Customer.FirstName), "FirstName");
                        bulk.ColumnMappings.Add(nameof(Customer.LastName), "LastName");
                        bulk.ColumnMappings.Add(nameof(Customer.DateOfBirth), "DateOfBirth");

                        bulk.EnableStreaming = true;
                        bulk.BatchSize = 10000;
                        bulk.NotifyAfter = 1000;
                        bulk.SqlRowsCopied += (sender, e) => Console.WriteLine("RowsCopied: " + e.RowsCopied);

                        await bulk.WriteToServerAsync(customerReader, ct);
                    }
                }
            }
        }
    }
}

Asynchronous Programming

January 5, 2018 19:31

Asynchronous Programming

using System;
using System.IO;
using System.Threading.Tasks;

internal class Program
{
private static void Main()
{
Task task = new Task(CallMethod);
task.Start();
task.Wait();
Console.ReadLine();
}

private static async void CallMethod()
{
string filePath = "D:\\sampleFile.txt";
Task<int> task = ReadFile(filePath);

Console.WriteLine(" Other Work 1");
Console.WriteLine(" Other Work 2");
Console.WriteLine(" Other Work 3");

int length = await task;
Console.WriteLine(" Total length: " + length);

Console.WriteLine(" After work 1");
Console.WriteLine(" After work 2");
}

private static async Task<int> ReadFile(string file)
{
int length = 0;

Console.WriteLine(" File reading is stating");
using (StreamReader reader = new StreamReader(file))
{
// Reads all characters from the current position to the end of the stream asynchronously
// and returns them as one string.
string s = await reader.ReadToEndAsync();

length = s.Length;
}
Console.WriteLine(" File reading is completed");
return length;
}
}

Categories