【ASP.NET】公司內部寄信不能到外部問題(Exchange WebServices API 寄信)

首先先感謝某個重要的人囉,讓我了解有Exchange WebServices API這東西 : )

問題

想要從程式寄信(SMTP)至外部信箱都會出現錯誤(內部寄信可以成功),一只Reply不成功,用了老半天才知道系統權限問題,系統管理者也不可能給我權限。思考著同個SMTP Server為什麼我Outlook卻可以寄到外部信箱,而SMTP方法卻不行,接著找關鍵字,才知道公司的Outlook是用Exchange Server來處理,到Nuget找到了Exchange WebServices API,發現功能滿強大的,其實就是把我們平常Outlook操作變程式化,這裡我只有用到寄信的方法,其它方法這裡不做多介紹。

Exchange WebServices寄信方法

先到Nuget找到相關套件。

裝了套件之後就是來寫寄信程式囉,不難,我寫成一個Class,可自行更改需要的參數。

using System.Net;
using Microsoft.Exchange.WebServices.Data;

    public class SendmailByOutLook
    {
        /// <summary>
        /// Exchange寄信
        /// </summary>
        /// <param name="MailUser">Windows帳號</param>
        /// <param name="MailPasswords">Windows密碼</param>
        /// <param name="MailRecipient">收件人</param>
        /// <param name="MailSubject">信件標題</param>
        /// <param name="MailMain">信件內容</param>
        /// <param name="MailFrom">寄件人自定義名稱(需要有該帳號權限)</param>
        public void SendMail(string MailUser, string MailPasswords, string MailRecipient, 
        string MailSubject, string MailMain, string MailFrom)
        {
            ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
            //Exchange Server 網域(AD)帳號密碼
            service.Credentials = new NetworkCredential(MailUser, MailPasswords);
            service.AutodiscoverUrl(MailFrom);

            EmailMessage emailMessage = new EmailMessage(service);
            
            //下行可以刪除,會以你登入網域帳號(AD)對應到寄件人
            emailMessage.From = MailFrom; 
            //目前參數寫單一收件者,可自行更改成List等方式一次寄多人
            emailMessage.ToRecipients.Add(MailRecipient); 
            emailMessage.Subject = MailSubject;
            emailMessage.Body = new MessageBody(MailMain);

            //Send
            emailMessage.SendAndSaveCopy();
        }
    }

當然引用方法很簡單,自行試試看囉。

SendmailByOutLook sbo = new SendmailByOutLook();

sbo.SendMail(MailUser, MailPasswords,
             MailRecipient, MailSubject, MailMain, MailFrom);

參考網址

Working with the EWS Managed API 2.0

Exchange Server Developer

【LeetCode】#189 Rotate Array(C#)

● 問題

Rotate an array of n elements to the right by k steps.

For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4].

Note:
Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.


● 思考點

k是多少就向右旋轉多少次,後來找到資料可以用Array的Reverse方法,可以更加速理解(效能也比較好)。


● Solution

public class Solution {
    public void Rotate(int[] nums, int k) {
        k = k % nums.Length;
        Array.Reverse(nums);

        Array.Reverse(nums, 0, k);
        Array.Reverse(nums, k, nums.Length - k);
    }
}

【LeetCode】#172 Factorial Trailing Zeroes(C#)

● 問題

Given an integer n, return the number of trailing zeroes in n!.

Note: Your solution should be in logarithmic time complexity.


● 思考點

求出n!共出現幾個0,時間複雜度需要考慮進去O(logn),這題主要找出5出現幾次(因任一偶數乘以5將會出現0)。


● Solution

public class Solution {
    public int TrailingZeroes(int n) {
        
        int Result = 0;
        
        while(n >= 5)
        {
            n /= 5;
            Result += n;
        }
        
        return Result;
    }
}

【LeetCode】#171 Excel Sheet Column Number(C#)

● 問題

Given a column title as appear in an Excel sheet, return its corresponding column number.

Example:
A -> 1
B -> 2
C -> 3
...
Z -> 26
AA -> 27
AB -> 28


● 思考點

先找出ASCII的基準點'A',接下來我們知道A-Z總共26個字母,表示26進位轉換。

Example1:
AB:26*1(A) + 2(B) = 28
BC:26*2(B) + 3(C) = 55
ABC:(26 * 1(A) = 26)  ([26 + 2(B)] * 26 = 728) (728 + 3(C) = 731)      
Example2:
AB:26*1(A) + 1*2(B) = 28
BC:26*2(B) + 1*3(C) = 55
ABC:676*1(A) + 26*2(B) + 1*3(C) = 731      


● Solution

(1)

public class Solution {
    public int TitleToNumber(string s) {
        
        int result = 0;
        
        for(int i = 0; i < s.Length; i++)
        {
            result = result * 26 + (s[i] - 'A' + 1);
        }
        
        return result;
    }
}

(2)

public class Solution {
    public int TitleToNumber(string s)
    {
        int result = 0;
        int exp = s.Length - 1;

        for (int i = 0; i < s.Length; i++)
        {
            double tmp = (s[i] - 'A' + 1);
            tmp = tmp * Math.Pow(26, exp--);
            result += Convert.ToInt32(tmp);
        }

        return result;
    }
}

【LeetCode】#168 Excel Sheet Column Title(C#)

● 問題

Given a positive integer, return its corresponding column title as appear in an Excel sheet.


● 思考點

要先了解ASCII所對應的字元,而我們不可能預先知道A的ASCII,所以把A當作基準點,接著轉換成ASCII比較妥當。


● Solution

public class Solution {
    public string ConvertToTitle(int n) {
    
        var  result = "";
        
        while(n > 0)
        {
            n--;
            result = Convert.ToChar((n % 26) + 'A') + result;
            n /= 26;
        }
        
        return result;
    }
}

設計模式基本原則

● 基本原則(1-5又稱SOLID)

  1. 單一職責原則 (Single Responsibility Principle)

    一個類別(Class),應該只有一個引起它變化的原因。建議介面一定要做到單職責。

  2. 開放、封閉原則 (OCP:Open Closed Principle)

    對於擴展是開放的 (Open for extension)
    對於修改是封閉的 (Closed for modification)

  3. 里氏(Liskov)代換原則 (LSP:Liskov Substitution Principle)

    子類別必須能替換父類別。
    只要父類能出現的地方子類就可以出現,而且替換為子類也不會產生任何錯誤或異常,使用者可能根本就不需要知道是父類還是子類。但是,反過來就不行,有子類出現的地方,父類未必就能適應。

  4. 介面隔離原則 (ISP:Interface Segregation Principle)

    客戶端(Client)不應該依賴它不需要的接口。
    類別間的依賴關係應該建立在最小的接口上。

  5. 依賴倒轉原則 (DIP:Dependency Inversion Principle)

    高階模組不應該依賴於低階模組,兩者都該依賴抽象。
    抽象不應該依賴於具體實作方式。
    具體實作方式則應該依賴抽象。

  6. 迪米特法則 (LoD:Law of Demeter)也稱為最少知識原則(Least Knowledge Principle,LKP)

    最少知識原則 Principle of Least Knowledge。

    【舉例】
    一個類應該對自己需要耦合或調用的類知道得最少,你(被耦合或調用的類)的內部是如何復雜都和我沒關係,那是你的事情,我就知道你提供的這麼多public方法,我就調用這麼多,其他的我一概不關心。

  7. 合成/聚合重覆使用原則 (CARP)(Composite/Aggregate Reuse Principle)

    多用合成/聚合,少用繼承。
    在兩個物件有 has-a (has-parts、is-part-of)關係時 => 合成/聚合 (A has a B)
    當兩個物件有 is-a (is-a-kind-of)關係時 => 繼承 (Superman is a kind of Person)
    合成 (Composite):A、B兩物件有合成關係時,表示其中一個物件消失(ex:書本),另一個物件也會消失(ex:章節)。
    聚合 (Aggregate):A、B兩物件有聚合關係時,表示其中一個物件消失(ex:球隊),另一個物件不會消失(ex:球員)。

● 設計模式(分三大類)

一、 創建型設計模式 (Creational Design Patterns)

1. 簡單工廠模式 (Simple Factory Pattern)
2. 工廠方法模式 (Factory Method Pattern)
3. 抽象工廠模式 (Abstract Factory Pattern)
4. 建造者模式(生成器模式) (Builder Pattern)
5. 原型模式 (Prototype Pattern)
6. 單例模式 (Singleton Pattern)

二、 結構型設計模式 (Structural Design Patterns)

1. 適配器模式 (Adapter Pattern)
2. 橋接模式 (Bridge Pattern)
3. 組合模式 (Composite Pattern)
4. 裝飾模式 (Decorator Pattern)
5. 外觀模式 (Facade Pattern)
6. 享元模式 (Flyweight Pattern)
7. 代理模式 (Proxy Pattern)

三、 行為型設計模式 (Behavioral Design Patterns)

1. 責任鏈模式 (Chain-of-responsibility Pattern)
2. 命令模式 (Command Pattern)
3. 解釋器模式 (Interpreter Pattern)
4. 迭代器模式 (Iterator Pattern)
5. 中介者模式 (Mediator Pattern)
6. 備忘錄模式 (Memento Pattern)
7. 觀察者模式 (發佈/訂閱模式) (Observer Pattern)
8. 狀態模式 (State Pattern)
9. 策略模式 (Strategy Pattern)
10. 模板方法模式 (Template Method Pattern)
11. 訪問者模式 (Visitor Pattern)

【LeetCode】#136 Single Number(C#)

● 問題

Given an array of integers, every element appears twice except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

● 思考點

在這陣列裡的數字都是成雙成對的,只有一個數字是出現一次的,用最好的計算時間找出該數字。
我一開始想到的是List或Dictionary方式來做,應該會採取Dictionary方式過濾。
找些資料後發現這題最好的方法是用XOR,也就是說重覆數字會變0,最後結果為出現一次的數字。

● Solution

【Dictionary】

public class Solution {
    public int SingleNumber(int[] nums) {
        
        var dict = new Dictionary<int, int>();
        
        for (var i = 0; i < nums.Length; i++)
        {
            if (dict.ContainsKey(nums[i]))
            {
                //重覆刪除
                dict.Remove(nums[i]);
            }
            else
            {
                dict.Add(nums[i], nums[i]);
            }
        }
        
        return dict.ElementAt(0).Value;
    }
}

【XOR】

public class Solution {
    public int SingleNumber(int[] nums) {
        
        var result = 0;
        
        for (var i = 0; i < nums.Length; i++)
        {
            //XOR重覆數字為0
            result ^= nums[i];
        }
        
        return result;
    }
}

【LeetCode】#104 Maximum Depth of Binary Tree(C#)

● 問題

Given a binary tree, find its maximum depth.

The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.

● 思考點

求出節點左、右葉子值(最大值),接著加一即求出。

● Solution

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left;
 *     public TreeNode right;
 *     public TreeNode(int x) { val = x; }
 * }
 */
 
public class Solution {
    public int MaxDepth(TreeNode root) {
        if (root == null) return 0;
        var leftDepth = MaxDepth(root.left) + 1;
        var rightDepth = MaxDepth(root.right) + 1;
        return (leftDepth > rightDepth) ? leftDepth : rightDepth;
    }
}

設計模式之禪-18.策略模式(Strategy Pattern)C#範例(筆記)

一、策略模式定義

策略模式(Strategy Pattern)是一種比較簡單的模式,也就是政策模式(Policy Pattern)。

定義:定義一組算法,將每個算法都封裝起來,使他們之間可以互換。

● Context封裝角色

它也叫做上下文角色,起承上啟下封裝作用,屏蔽高層模塊對策略、算法的直接訪問,封裝可能存在的變化。

● Strategy抽象策略角色

策略、算法家族的抽象,通常為接口,定義每個策略或算法必須具有的方法和屬性。

● ConcreteStrategy具體策略角色

實現抽象策略中的操作,該類含有具體的算法。

二、策略模式範例情境

提到三國為範例,每一個方法為一個妙計。

public interface IStrategy
{
    //每個妙計都是一個可執行的算法
    void operate();
}

//第一妙計:找喬國老開後門
public class BackDoor : IStrategy
{
    public void operate()
    {
        Console.WriteLine("找喬國老幫忙,讓吳國太給孫權施加壓力");
    }
}

//第二妙計:吳國太開綠燈
public class GivenGreenLight : IStrategy
{
    public void operate()
    {
        Console.WriteLine("求吳國太開綠燈,放行!");
    }
}

//第三妙計:讓新娘子權夫人斷後
public class BlockEnemy : IStrategy
{
    public void operate()
    {
        Console.WriteLine("孫夫人斷後,擋住追兵");
    }
}

現在,妙計都有了,缺少兩個配角,一個承裝妙計的錦囊(錦囊妙計),一個是執行人趙雲。趙雲取出錦囊中的妙計,接著執行,獲勝,來看看如何實現。

在類別圖中加入一個Context封裝類(也就是錦囊),其承裝三個策略,方便趙雲使用。如圖下

public class Context
{
    //構造函數,你要使用哪個妙計
    private IStrategy strategy;

    public Context(IStrategy strategy)
    {
        this.strategy = strategy;
    }

    //使用計謀
    public void operate()
    {
        this.strategy.operate();
    }
}

三個妙計有了錦囊也有了,接著趙雲取出妙計去執行項目。

public class ZhaoYun
{
    class Program
    {
        static void Main(string[] args)
        {
            Context context;

            //剛到吳國拆第一個
            Console.WriteLine("---剛到吳國時候拆第一個妙計---");
            context = new Context(new BackDoor());
            //執行第一個
            context.operate();

            //劉備拆第二個
            Console.WriteLine("---劉備拆了第二個---");
            context = new Context(new GivenGreenLight());
            //執行第二個
            context.operate();

            //孫權拆第三個
            Console.WriteLine("---孫權拆了第三個---");
            context = new Context(new BlockEnemy());
            //執行第三個
            context.operate();

            Console.ReadKey();
        }
    }
}

執行結果如下:

---剛到吳國時候拆第一個妙計---
找喬國老幫忙,讓吳國太給孫權施加壓力
---劉備拆了第二個---
求吳國太開綠燈,放行!
---孫權拆了第三個---
孫夫人斷後,擋住追兵

整個故事過程為策略模式。