小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

通過谷歌服務(wù)安排郵寄活動(dòng)

 Levy_X 2019-08-06

簡(jiǎn)介

交易者可能希望安排一次郵寄活動(dòng),以維持與其他交易者、訂戶、客戶或朋友的業(yè)務(wù)關(guān)系。此外,可能需要發(fā)送截圖、日志或報(bào)告。這些任務(wù)可能不是最經(jīng)常出現(xiàn)的任務(wù),但是擁有這樣的特性顯然是一個(gè)優(yōu)勢(shì)。在這里使用方便的MQL工具絕對(duì)是困難的,甚至是完全不可能的。在本文的最后,我們將回到使用專門的MQL工具來解決此任務(wù)的問題。在此之前,我們將使用MQL和C#的組合。這將使我們相對(duì)容易地編寫必要的代碼并將其連接到終端,此外,它還將設(shè)置一個(gè)與此連接相關(guān)的非常有趣的挑戰(zhàn)。

本文面向初學(xué)者和中層開發(fā)人員,他們希望加深他們對(duì)編寫庫(kù)的知識(shí),并將它們與終端集成,同時(shí)更加熟悉Google服務(wù)。

設(shè)置任務(wù)

現(xiàn)在,讓我們更準(zhǔn)確地定義我們將要做什么,有一個(gè)可更新的聯(lián)系人列表,允許用戶向列表中的任何聯(lián)系人發(fā)送一次或多次帶有附件的電子郵件。需要考慮的事項(xiàng):

  • 列表中的某些聯(lián)系人可能沒有地址,或者地址不正確。此外,可能有多個(gè)地址。
  • 可以更改列表-可以添加或刪除聯(lián)系人。
  • 聯(lián)系人可以重復(fù)。
  • 它們也可能被排除在郵寄活動(dòng)之外,而留在列表中。換句話說,聯(lián)系人的活動(dòng)應(yīng)該是可調(diào)整的。
  • 此外,列表中肯定會(huì)包含與相關(guān)任務(wù)無關(guān)的聯(lián)系人。

實(shí)施列表管理是最明顯的任務(wù)。我們這里有什么選擇?

  1. HDD 數(shù)據(jù)庫(kù)或 CSV 文件不方便且不夠可靠。它并不總是可用的,可能需要一個(gè)額外的軟件來管理這樣的存儲(chǔ)。
  2. 一個(gè)特殊網(wǎng)站的數(shù)據(jù)庫(kù),有一個(gè)Joomla類型的CMS,這是一個(gè)很好的解決方案。數(shù)據(jù)受到保護(hù),可以從任何地方訪問。此外,電子郵件可以很容易地從網(wǎng)站發(fā)送。然而,也有一個(gè)顯著的缺點(diǎn)。與此類網(wǎng)站交互需要一個(gè)特殊的附加組件,這樣的附加組件可能非常大,并且充滿了安全漏洞。換句話說,這里必須有可靠的基礎(chǔ)設(shè)施。
  3. 使用現(xiàn)成的 Google 服務(wù)。在那里,您可以安全地存儲(chǔ)和管理聯(lián)系人,以及從不同的設(shè)備訪問他們。尤其是,您可以形成各種列表(組)并發(fā)送電子郵件。這就是我們舒適工作所需要的一切,所以我們堅(jiān)持這個(gè)選擇。

與 Google 交互有大量的文檔記錄,例如這里。要開始使用Google,請(qǐng)注冊(cè)一個(gè)帳戶并在那里創(chuàng)建聯(lián)系人列表,該列表應(yīng)包含我們要向其發(fā)送電子郵件的聯(lián)系人。在“聯(lián)系人”中,創(chuàng)建具有特定名稱的組,例如“Forex”,并將所選聯(lián)系人添加到該組中。每個(gè)聯(lián)系人都可以保存多個(gè)數(shù)據(jù)以備以后使用。不幸的是,如果用戶仍然需要一個(gè)額外的數(shù)據(jù)字段,則無法創(chuàng)建它,這不會(huì)造成不便,因?yàn)橛泻芏鄶?shù)據(jù)字段可用,稍后我將演示如何使用它們,

現(xiàn)在是時(shí)候開始主要任務(wù)了。

谷歌方面的準(zhǔn)備工作

假設(shè)我們已經(jīng)有一個(gè)谷歌帳戶,使用谷歌“開發(fā)控制臺(tái)”恢復(fù)項(xiàng)目開發(fā)。在這里您可以詳細(xì)了解如何使用控制臺(tái)和開發(fā)項(xiàng)目,當(dāng)然,上面的鏈接將介紹另一個(gè)項(xiàng)目。我們的項(xiàng)目需要一個(gè)名字,讓它名為 ' WorkWithPeople'。我們還需要其他服務(wù),在此階段,啟用以下選項(xiàng):

  • People API
  • Gmail API

第一個(gè)提供了對(duì)聯(lián)系人列表的訪問(實(shí)際上,它也提供了對(duì)其他事物的訪問,但我們只需要列表)。有另一個(gè)用于訪問聯(lián)系人列表的服務(wù)-Contacts API,但目前不建議使用,因此我們不注意它。

顧名思義,第二個(gè)服務(wù)提供對(duì)郵件的訪問。

啟用服務(wù)并獲取授予應(yīng)用程序訪問它們的密鑰。不需要寫下來或者記住,以 json 格式下載附件,其中包含訪問 Google 資源所需的所有數(shù)據(jù),包括這些密鑰。將文件保存在磁盤上,也許可以給它一個(gè)更有意義的名稱。在我的例子中,它被稱為“WorkwithPeople_gmail.json”。這就完成了與谷歌的直接操作,我們已經(jīng)創(chuàng)建了帳戶、聯(lián)系人列表和項(xiàng)目,并獲得了訪問文件。

現(xiàn)在,讓我們繼續(xù)在 VS 2017 工作。

項(xiàng)目和開發(fā)包

打開 VS 2017并創(chuàng)建一個(gè)標(biāo)準(zhǔn)Class Library(.NET Framework)項(xiàng)目。以任何可記憶的方式命名它(在我的例子中,它與Google項(xiàng)目名稱“WorkwithPeople”一致,盡管這不是必須的)。使用NuGet立即安裝其他軟件包:

  • Google.Apis
  • Google.Apis.People.v1
  • Google.Apis.PeopleService.v1
  • Google.Apis.Gmail.v1
  • MimeKit

    在安裝過程中,Nuget提供安裝相關(guān)軟件包的服務(wù),要對(duì)此表示同意。在我們的例子中,該項(xiàng)目接收谷歌的軟件包,用于處理聯(lián)系人和管理電子郵件。現(xiàn)在我們準(zhǔn)備好開發(fā)代碼了。

    訪問聯(lián)系人

    讓我們從輔助類開始,如果我們考慮到某個(gè)谷歌聯(lián)系人所包含的數(shù)據(jù)量,那么很明顯,我們的任務(wù)不需要它的主要部分,我們需要一個(gè)聯(lián)系人姓名和地址發(fā)送電子郵件。事實(shí)上,我們還需要來自另一個(gè)欄位的數(shù)據(jù),但稍后會(huì)討論更多。

    相應(yīng)的類可以如下所示:

    namespace WorkWithPeople {    internal sealed class OneContact     {         public OneContact(string n, string e)         {             this.Name = n;             this.Email = e;         }         public string Name { get; set; }         public string Email { get; set; }     } }

    有兩個(gè)“字符串”類型的屬性存儲(chǔ)聯(lián)系人姓名和地址,以及一個(gè)簡(jiǎn)單的構(gòu)造函數(shù),其中包含兩個(gè)參數(shù)來初始化它們,沒有實(shí)現(xiàn)另外的檢查,它們將在其它地方進(jìn)行。

    讀取聯(lián)系人列表時(shí)會(huì)創(chuàng)建簡(jiǎn)單元素列表。這允許根據(jù)這個(gè)新構(gòu)建的列表的數(shù)據(jù)進(jìn)行郵件活動(dòng)。如果要更新列表,請(qǐng)刪除所有列表元素,然后重復(fù)從Google帳戶讀取和選擇數(shù)據(jù)的操作。

    還有另一個(gè)輔助類,聯(lián)系人列表可能包含無效的電子郵件地址,或者根本沒有地址,在發(fā)送電子郵件之前,我們需要確保地址正確無誤,讓我們開發(fā)新的輔助類來實(shí)現(xiàn)這一點(diǎn):

    namespace WorkWithPeople
    {    
        internal static class ValidEmail
        {
            public stati cbool IsValidEmail(this string source) => !string.IsNullOrEmpty(source) && new System.ComponentModel.DataAnnotations.EmailAddressAttribute().IsValid(source);
        }
    }
    
    

    為了執(zhí)行檢查,我們使用可用的工具,盡管我們也可以使用正則表達(dá)式。為了便于進(jìn)一步使用,我們開發(fā)了代碼作為擴(kuò)展方法。由于不難猜測(cè),如果包含郵件地址的字符串通過檢查,則該方法返回true,否則返回false。現(xiàn)在是時(shí)候轉(zhuǎn)到代碼的主要部分了。

    訪問和使用服務(wù)

    我們已經(jīng)創(chuàng)建了項(xiàng)目,獲取了密鑰,并下載了用于授權(quán)應(yīng)用程序的JSON文件。因此,讓我們創(chuàng)建一個(gè)新的類ContactsPeople并將適當(dāng)?shù)某绦蚣砑拥轿募校?/p>

    using System; using System.Collections.Generic; using System.Linq; using System.IO; using System.Net.Mail; using System.Text; using System.Threading; using System.Threading.Tasks; using Google.Apis.Auth.OAuth2; using Google.Apis.People.v1; using Google.Apis.Services; using Google.Apis.Util.Store; using Google.Apis.Http; using Google.Apis.PeopleService.v1; using Google.Apis.PeopleService.v1.Data; using Google.Apis.Gmail.v1; using Google.Apis.Gmail.v1.Data; namespace WorkWithPeople {     internal sealed class ContactsPeople     { public static string Applicationname { get; } = 'WorkWithPeople'; .....

    添加包含Google項(xiàng)目名稱的靜態(tài)屬性,此靜態(tài)屬性為只讀。

    將封閉字段和枚舉添加到類:

            private enum             PersonStatus
            {
                Active,
                Passive
            };
            private string           _groupsresourcename;
            private List<OneContact> _list = new List<OneContact>();
            private UserCredential   _credential;
            private PeopleService    _pservice;
            private GmailService     _gservice;
    

    枚舉用于將聯(lián)系人標(biāo)記為“主動(dòng)”(接收電子郵件)和“被動(dòng)”(不接收電子郵件)。其他封閉字段:

    • _groupsresourcename. 與“聯(lián)系人”中創(chuàng)建的組相對(duì)應(yīng)的Google資源名稱,(在我們的例子中,所選的組名是“Forex”)。
    • _list. 郵寄活動(dòng)要應(yīng)用到的聯(lián)系人列表。
    • _credential. 應(yīng)用 'powers'.
    • _pservice, _gservice. 用于處理聯(lián)系人和郵件的服務(wù)。

    讓我們編寫主要工作函數(shù)的代碼:

            publicint WorkWithGoogle(string credentialfile,                                    string user,                                    string filedatastore,                                    string groupname,                                    string subject,                                    string body,                                    bool   isHtml,                                    List<string> attach = null)         { ...

    其參數(shù)是:

    • credentialfile. 訪問包含用于訪問服務(wù)的所有數(shù)據(jù)的JSON文件的名稱和路徑,它以前是從谷歌賬戶下載的。
    • user. 谷歌帳戶名 - xxxxx@gmail.com地址。
    • filedatastore. 輔助文件夾的名稱-用戶PC上的存儲(chǔ)(可以是任意的)。該文件夾是在 AppData(%APPDATA%)中創(chuàng)建的,其中包含包含附加訪問數(shù)據(jù)的文件。
    • groupname. 我們創(chuàng)建的郵寄活動(dòng)的聯(lián)系人組的名稱,在我們的例子中,它是“Forex”。
    • subject, body, isHtml. 郵件主題和文本,以及是否以HTML格式編寫。
    • attach. 附件列表。

    返回值 - 已發(fā)送電子郵件的數(shù)量。開始編寫函數(shù)代碼:

                if (!File.Exists(credentialfile))
                    throw (new FileNotFoundException('Not found: '   credentialfile));
                using (var stream = new FileStream(credentialfile, FileMode.Open, FileAccess.Read))
                {
                    if (_credential == null) {
                        _credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                            GoogleClientSecrets.Load(stream).Secrets,
                            new[]
                            {
                                GmailService.Scope.GmailSend,
                                PeopleService.Scope.ContactsReadonly
                            },
                            user,
                            CancellationToken.None,
                            new FileDataStore(filedatastore)).Result;
                            CreateServicies();
                    }
                    else if (_credential.Token.IsExpired(Google.Apis.Util.SystemClock.Default)) {
                        bool refreshResult = _credential.RefreshTokenAsync(CancellationToken.None).Result;
                        _list.Clear();
                        if (!refreshResult) return 0;   
                        CreateServicies();
                    }
                    
                }// using (var stream = new FileStream(credentialfile, FileMode.Open, FileAccess.Read))
    

    請(qǐng)注意定義應(yīng)請(qǐng)求服務(wù)的訪問權(quán)限的字符串?dāng)?shù)組:

    • GmailService.Scope.GmailSend. 這是發(fā)送電子郵件的權(quán)限。
    • PeopleService.Scope.ContactsReadonly. 以只讀模式訪問聯(lián)系人。

    另外,注意調(diào)用 GoogleWebAuthorizationBroker.AuthorizeAsync. 它的名稱表明調(diào)用是異步執(zhí)行的。

    請(qǐng)注意,如果以前收到的令牌已過期,代碼將更新它并從以前形成的 _list 中刪除所有對(duì)象。

    輔助的 CreateServicies() 函數(shù)創(chuàng)建并初始化必要的對(duì)象:

            private void         CreateServicies()         {             _pservice = new PeopleService(new BaseClientService.Initializer()             {                 HttpClientInitializer = _credential,                 ApplicationName = Applicationname             });             _gservice = new GmailService(new BaseClientService.Initializer()             {                 HttpClientInitializer = _credential,                 ApplicationName = Applicationname             });         }

    如我們所見,在執(zhí)行上面顯示的代碼段后,我們可以訪問必要的服務(wù):

     - 使用JSON數(shù)據(jù)文件,我們首先請(qǐng)求“powers”,并將它們保存在_credential字段中。然后我們調(diào)用將“power”和項(xiàng)目名稱字段傳遞給它們的服務(wù)構(gòu)造函數(shù)作為初始化列表。

    現(xiàn)在是獲取為郵寄活動(dòng)選擇的組的聯(lián)系人列表的時(shí)間:

                try {
                      if (_list.Count == 0)
                        GetPeople(_pservice, null, groupname);                     
                }
                catch (Exception ex) {
                    ex.Data.Add('call GetPeople: ', ex.Message);
                    throw;
                }
    #if DEBUG
                int i = 1;
                foreach (var nm in _list) {
                    Console.WriteLine('{0} {1} {2}', i  , nm.Name, nm.Email);
                }
    #endif
                if (_list.Count == 0) {
                    Console.WriteLine('Sorry, List is empty...');
                    return 0;
                }
    

    GetPeople(…)函數(shù)(稍后描述)是要填充存儲(chǔ)聯(lián)系人的 _list。此函數(shù)用作異常源,因此其塊包裝在try代碼塊中。在已連接的程序集中未檢測(cè)到異常類型,因此catch塊以最一般的形式寫入。換句話說,我們不必在這里包括所有可能發(fā)生的事件,這樣就不會(huì)丟失用于調(diào)試的有價(jià)值的數(shù)據(jù)。因此,向異常添加您認(rèn)為必要的數(shù)據(jù)并重新激活它。

    請(qǐng)記住,只有當(dāng)它為空時(shí)(即當(dāng)它接收到新令牌或更新舊令牌時(shí)),才會(huì)更新_ list。

    下一個(gè)塊僅對(duì)調(diào)試版本執(zhí)行. 整個(gè)形成的列表只顯示在控制臺(tái)中。

    最后一塊很明顯,如果名單仍然空白,則進(jìn)一步的工作沒有點(diǎn),并被相應(yīng)的信息所阻止。

    該函數(shù)以形成一個(gè)傳出電子郵件并進(jìn)行郵件活動(dòng)而結(jié)束:

                using (MailMessage mail = new MailMessage             {                 Subject = subject,                 Body = body,                 IsBodyHtml = isHtml             })  // MailMessage mail = new MailMessage             {                 if (attach != null)                 {                     foreach (var path in attach)                         mail.Attachments.Add(new Attachment(path));                 } //  if (attach != null)                 foreach (var nm in _list)                     mail.To.Add(new MailAddress(nm.Email, nm.Name));                 try                 {                     SendOneEmail(_gservice, mail);                 }                 catch (Exception ex)                 {                     ex.Data.Add('call SendOneEmail: ', ex.Message);                     throw;                 }             }// using (MailMessage mail = new MailMessage

    此處創(chuàng)建了MailMessage庫(kù)類的實(shí)例。接下來是它隨后的初始化和填充字段。如果有附件,則添加附件列表。最后,形成前一階段獲得的郵件列表。

    郵寄由SendOneEmail(…)稍后描述的函數(shù)執(zhí)行。就像GetPeople(…)函數(shù)一樣,它也可能成為異常源。因此,它的調(diào)用也被包裝在try代碼中,而在catch中的處理也是類似的。

    此時(shí),WorkWithGoogle(…) 主函數(shù)的工作被認(rèn)為是完成的,它返回_list.Count值,假設(shè)電子郵件消息從列表發(fā)送到每個(gè)聯(lián)系人。

    填寫聯(lián)系人列表

    獲取訪問權(quán)限后,準(zhǔn)備好填寫_list,這是通過以下函數(shù)完成的:

            private void         GetPeople(PeopleService service, string pageToken, string groupName)
            {
               ...
    

    其參數(shù)是:

    • service. 指向先前創(chuàng)建的Google聯(lián)系人訪問類的鏈接。
    • pageToken. 可能有多個(gè)聯(lián)系人。此參數(shù)告訴開發(fā)人員聯(lián)系人列表占用多個(gè)頁(yè)面。
    • groupName. 我們感興趣的聯(lián)系人組的名稱,

    第一次使用 pageToken = NULL 調(diào)用函數(shù),如果對(duì) Google 的請(qǐng)求隨后返回值不同于NULL的令牌,則遞歸調(diào)用該函數(shù)。

                if (string.IsNullOrEmpty(_groupsresourcename))             {                 ContactGroupsResource groupsResource = new ContactGroupsResource(service);                 ContactGroupsResource.ListRequest listRequest = groupsResource.List();                 ListContactGroupsResponse response = listRequest.Execute();                 _groupsresourcename = (from gr in response.ContactGroups                                        where string.Equals(groupName.ToUpperInvariant(), gr.FormattedName.ToUpperInvariant())                                        select gr.ResourceName).Single();                 if (string.IsNullOrEmpty(_groupsresourcename))                     throw (new MissingFieldException($'Can't find GroupName: {groupName}'));             }// if (string.IsNullOrEmpty(_groupsresourcename))

    我們需要通過組名找到一個(gè)資源名,為此,請(qǐng)求所有資源的列表,并在簡(jiǎn)單的 lambda 表達(dá)式中找到所需的資源。請(qǐng)注意,應(yīng)該只有一個(gè)具有所需名稱的資源,如果在工作期間找不到資源,則啟用異常。

    Google.Apis.PeopleService.v1.PeopleResource.ConnectionsResource.ListRequest peopleRequest =
                    new Google.Apis.PeopleService.v1.PeopleResource.ConnectionsResource.ListRequest(service, 'people/me')
                    {
                        PersonFields = 'names,emailAddresses,memberships,biographies'
                    };
                if (pageToken != null) {
                    peopleRequest.PageToken = pageToken;
                }
    
    

    讓我們構(gòu)造對(duì)谷歌的請(qǐng)求,以獲得必要的列表,為此,請(qǐng)指定我們感興趣的谷歌聯(lián)系人數(shù)據(jù)中的字段:

    • names, emailAddresses. 用于創(chuàng)建 OneContact 類的實(shí)例.
    • memberships. 檢查聯(lián)系人是否屬于我們組。
    • biographies. 選擇此字段是為了管理聯(lián)系人活動(dòng),盡管它是為了存儲(chǔ)聯(lián)系人的個(gè)人簡(jiǎn)歷而設(shè)計(jì)的。為了使聯(lián)系人被識(shí)別為活動(dòng)聯(lián)系人并向其地址發(fā)送電子郵件,字段必須以一開頭。在任何其他情況下,即使聯(lián)系人位于必要的組中,也被認(rèn)為是被動(dòng)的和忽略的。沒有必要為此使用這個(gè)特定的字段,在我們的例子中,它的選擇可能是因?yàn)樗氖褂孟鄬?duì)較少。這對(duì)于用戶管理郵件活動(dòng)非常方便,因?yàn)樗试S“啟用/禁用”某些聯(lián)系人。

    最后,提出請(qǐng)求:

                var request = peopleRequest.Execute();             var list1 = from person in request.Connections                      where person.Biographies != null                      from mem in person.Memberships                      where string.Equals(_groupsresourcename, mem.ContactGroupMembership.ContactGroupResourceName) &&                            PersonActive(person.Biographies.FirstOrDefault()?.Value) == PersonStatus.Active                      let name = person.Names.First().DisplayName                      orderby name                      let email = person.EmailAddresses?.FirstOrDefault(p => p.Value.IsValidEmail())?.Value                      where !string.IsNullOrEmpty(email)                      select new OneContact(name, email);             _list.AddRange(list1);             if (request.NextPageToken != null) {                 GetPeople(service, request.NextPageToken, groupName);             }         }//void GetPeople(PeopleService service, string pageToken, string groupName)

    發(fā)出請(qǐng)求并對(duì) lambda 表達(dá)式中的必要數(shù)據(jù)進(jìn)行排序,它看起來相當(dāng)笨重,但實(shí)際上相當(dāng)簡(jiǎn)單。一個(gè)聯(lián)系人應(yīng)該有一個(gè)非零的個(gè)人簡(jiǎn)歷,在正確的組中,是一個(gè)活躍的聯(lián)系人,并有一個(gè)正確的地址。讓我們?cè)谶@里展示通過“biographies”字段內(nèi)容定義單個(gè)聯(lián)系人的“active/passive”狀態(tài)的功能:

            private PersonStatus PersonActive(string value)
            {
                try {
                    switch (Int32.Parse(value))
                    {
                        case 1:
                            return PersonStatus.Active;
                        default:
                            return PersonStatus.Passive;
                    }
                }
                catch (FormatException)   { return PersonStatus.Passive; }
                catch (OverflowException) { return PersonStatus.Passive; }
            }//PersonStatus PersonActive(string value)
    

    這是項(xiàng)目中唯一一個(gè)不尋求重新啟用異常(嘗試在現(xiàn)場(chǎng)處理其中一些異常)的函數(shù)。

    我們快完成了!將獲得的列表添加到_list中,如果沒有讀取所有聯(lián)系人,則使用新的標(biāo)記值遞歸調(diào)用函數(shù)。

    發(fā)送電子郵件

    這由以下輔助函數(shù)執(zhí)行:

            private void SendOneEmail(GmailService service, MailMessage mail)         {             MimeKit.MimeMessage mimeMessage = MimeKit.MimeMessage.CreateFromMailMessage(mail);             var encodedText = Base64UrlEncode(mimeMessage.ToString());             var message = new Message { Raw = encodedText };             var request = service.Users.Messages.Send(message, 'me').Execute();         }//  bool SendOneEmail(GmailService service, MailMessage mail)

      它的調(diào)用如上所述,這個(gè)簡(jiǎn)單函數(shù)的目的是為發(fā)送和執(zhí)行郵件活動(dòng)準(zhǔn)備電子郵件,此外,該函數(shù)還具有所有“繁重”的準(zhǔn)備工作。不幸的是,Google不接受MailMessage類形式的數(shù)據(jù),因此,以可接受的形式準(zhǔn)備數(shù)據(jù)并對(duì)其進(jìn)行編碼。MimeKit程序集包括執(zhí)行編碼的工具。但是,我相信使用一個(gè)我們可以使用的簡(jiǎn)單函數(shù)要容易得多,我不會(huì)在這里展示它,因?yàn)樗芎?jiǎn)單。請(qǐng)注意在Service.Users.Messages.Send調(diào)用中的string類型的userId,它等于“me”的特殊值,允許Google訪問您的帳戶以獲取發(fā)送者數(shù)據(jù)。

      這就結(jié)束了對(duì)ContactsPeople類的分析,其余的函數(shù)是輔助的,因此沒有必要停留在它們上面。

      終端連接器

      唯一剩下的問題是將(未完成的)組件連接到終端。乍一看,任務(wù)很簡(jiǎn)單,定義幾個(gè)靜態(tài)方法,編譯項(xiàng)目并將其復(fù)制到終端的庫(kù)文件夾中。從MQL代碼調(diào)用程序集的靜態(tài)方法。但我們究竟應(yīng)該復(fù)制什么呢?有一個(gè)dll庫(kù)形式的程序集。在我們的工作中,NuGet還下載了十幾個(gè)程序集。有一個(gè)JSON文件存儲(chǔ)用于訪問Google的數(shù)據(jù)。讓我們嘗試將整個(gè)集合復(fù)制到“Libraries”文件夾。創(chuàng)建一個(gè)基本的MQL腳本(這里沒有附加代碼的意義),然后嘗試從程序集調(diào)用靜態(tài)方法。異常!沒有找到 Google.Apis.dll,這是一個(gè)非常令人不快的驚喜,這意味著CLR無法找到所需的程序集,盡管它與我們的主程序集位于同一文件夾中。為什么會(huì)這樣?不值得詳細(xì)研究這里的情況。所有對(duì)細(xì)節(jié)感興趣的人都可以在 Richter 的名著中找到它們(在關(guān)于尋找私有程序庫(kù)的章節(jié)中)。

      已經(jīng)有許多與 MetaTrader 一起工作的功能完備的.NET應(yīng)用程序的例子,在那里也發(fā)生了這樣的問題。它們是怎么解決的呢?在這里通過在.NET應(yīng)用程序和MQL程序之間創(chuàng)建通道解決了這個(gè)問題,而這里使用了一種基于事件的模式。我可以建議使用類似的方法,使用命令行將所需數(shù)據(jù)從MQL程序傳遞到.NET應(yīng)用程序。

      但值得考慮的是更“優(yōu)雅”,簡(jiǎn)單和普遍的解決方案。我的意思是使用 AppDomain.AssemblyResolve事件管理程序集下載。當(dāng)執(zhí)行要求無法按名稱綁定程序集時(shí),會(huì)發(fā)生此事件。在這種情況下,事件處理程序可以從另一個(gè)文件夾(擁有處理程序知道的地址)加載和返回程序集。因此,在這里提出一個(gè)相當(dāng)漂亮的解決方案:

      1. 在 “Libraries” 文件夾中創(chuàng)建一個(gè)具有不同名稱的文件夾(在我的例子中,它是“WorkWithPeople”),
      2. 將其方法導(dǎo)入到帶有MQL的文件中的程序集復(fù)制到 “Libraries”文件夾。
      3. 所有其他項(xiàng)目程序集,包括包含訪問Google服務(wù)數(shù)據(jù)的JSON文件,都被復(fù)制到“WorkWithPeople”文件夾中。
      4. 讓libraries文件夾中的主程序集知道它應(yīng)該在哪里查找其他程序集 - “WorkWithPeople”文件夾的完整路徑。

      這樣,我們就得到了一個(gè)可行的解決方案,而不會(huì)把“Libraries”文件夾弄亂。剩下的就是在代碼中實(shí)現(xiàn)決策了。

      控制類

      讓我們創(chuàng)建一個(gè)靜態(tài)類

          public static class Run
          {
      
              static Run() {
                  AppDomain.CurrentDomain.AssemblyResolve  = ResolveAssembly;
              }// Run()
      

      并向其中添加事件處理程序,以便它盡快出現(xiàn)在處理程序鏈中。讓我們定義處理程序本身:

              static Assembly ResolveAssembly(object sender, ResolveEventArgs args) {             String dllName = new AssemblyName(args.Name).Name '.dll';             return Assembly.LoadFile(Path.Combine(_path, dllName) );         }// static Assembly ResolveAssembly(object sender, ResolveEventArgs args)

      現(xiàn)在,每當(dāng)檢測(cè)到程序集時(shí),都會(huì)調(diào)用此處理程序。其目標(biāo)是下載并返回程序集,該程序集結(jié)合了_path變量和計(jì)算名稱之間的路徑?,F(xiàn)在,只有處理程序找不到程序集時(shí)才會(huì)出現(xiàn)異常。

      初始化函數(shù)如下:

      WorkwithPeoplepublic static void Initialize(string Path, string GoogleGroup, string AdminEmail, string Storage)
              {
                  if (string.IsNullOrEmpty(Path) ||
                      string.IsNullOrEmpty(GoogleGroup) ||
                      string.IsNullOrEmpty(AdminEmail) ||
                      string.IsNullOrEmpty(Storage)) throw (new MissingFieldException('Initialize: bad parameters'));
                  _group = GoogleGroup;
                  _user = AdminEmail;
                  _storage = Storage;
                  _path = Path;
              }//  Initialize(string Path, string GoogleGroup, string AdminEmail, string Storage)
      
      

      在嘗試發(fā)送電子郵件之前,應(yīng)首先調(diào)用此函數(shù),其參數(shù)是:

      • Path. 處理程序查找程序集以及用于訪問Google的數(shù)據(jù)文件所在的路徑。
      • GoogleGroup. 用于郵寄的聯(lián)系人中的組的名稱。
      • AdminEmail. 帳戶名/郵件地址(xxx@google.com),代表該帳戶進(jìn)行郵件發(fā)送。
      • Storage. 存儲(chǔ)一些附加數(shù)據(jù)的輔助文件的名稱。

      所有描述的參數(shù)不應(yīng)為空字符串,否則將激活異常。

      為包含的文件創(chuàng)建一個(gè)列表和一個(gè)簡(jiǎn)單的添加函數(shù):

      public static void AddAttachment (string attach) { _attachList.Add(attach);}

      該函數(shù)沒有錯(cuò)誤檢查工具,因?yàn)樗幚淼氖窃?MetaTrader 環(huán)境中初步創(chuàng)建的屏幕截圖和其他文件。假設(shè)這是由終端中工作的控制工具完成的。

      讓我們馬上創(chuàng)建一個(gè)郵寄對(duì)象

      static ContactsPeople _cContactsPeople = new ContactsPeople();
      
      

      并通過調(diào)用函數(shù)來執(zhí)行:

      public static int DoWork(string subject, string body, bool isHtml = false) {             if (string.IsNullOrEmpty(body))                 throw (new MissingFieldException('Email body null or empty'));             int res = 0;             if (_attachList.Count > 0) {                 res = _cContactsPeople.WorkWithGoogle(Path.Combine(_path, 'WorkWithPeople_gmail.json'),                     _user,                     _storage,                     _group,                     subject,                     body,                     isHtml,                     _attachList);                 _attachList.Clear();             } else {                 res = _cContactsPeople.WorkWithGoogle(Path.Combine(_path, 'WorkWithPeople_gmail.json'),                     _user,                     _storage,                     _group,                     subject,                     body,                     isHtml);             }// if (_attachList.Count > 0) ... else ...             return res;         }// static int DoWork(string subject, string body, bool isHtml = false)

      輸入?yún)?shù)如下:

      • subject. 電子郵件主題。
      • body. 電子郵件文本。
      • isHtml. 電子郵件是否具有HTML格式。

      有兩個(gè)選項(xiàng)可以調(diào)用_cContactsPeople.WorkWithGoogle,具體取決于電子郵件功能附件。調(diào)用的第一個(gè)參數(shù)特別有趣:

      Path.Combine(_path, 'WorkWithPeople_gmail.json')

      這是包含用于訪問Google服務(wù)的數(shù)據(jù)的文件的完整路徑。

      DoWork(…)函數(shù)返回已發(fā)送電子郵件的數(shù)量。

      除用于訪問Google的數(shù)據(jù)文件外,VS 2017的整個(gè)項(xiàng)目位于所附的google.zip檔案中。

      MetaTrader 方面的準(zhǔn)備工作

      程序集代碼已就緒,讓我們繼續(xù)到終端,在那里創(chuàng)建一個(gè)簡(jiǎn)單的腳本。可以這樣編寫(跳過開頭部分代碼):

      #import 'WorkWithPeople.dll' void OnStart()   {    string scr = 'scr.gif';    string fl = TerminalInfoString(TERMINAL_DATA_PATH) '\\MQL5\\Files\\';    ChartScreenShot(0, scr, 800, 600);      Run::Initialize('e:\\Forex\\RoboForex MT5 Demo\\MQL5\\Libraries\\WorkWithPeople\\' ,'Forex' ,'ХХХХХХ@gmail.com' ,'WorkWithPeople' );    Run::AddAttachment(fl scr);    int res = Run::DoWork('some subj' , 'Very big body' , false );    Print('result: ', res);     }

      代碼非常清楚。導(dǎo)入程序集。我們要做的第一件事是初始化它,添加先前制作的屏幕截圖并執(zhí)行郵件發(fā)送。完整的代碼可以在附加文件 google_test1.mq5中找到。

      另一個(gè)例子是在M5上工作的指標(biāo),每次檢測(cè)到新燭形時(shí)都會(huì)發(fā)送帶有屏幕截圖的電子郵件:

      #import 'WorkWithPeople.dll'
      
      input string scr='scr.gif';
      
      string fp;
      
      int OnInit()
        {
         fp=TerminalInfoString(TERMINAL_DATA_PATH) '\\MQL5\\Files\\';
         Run::Initialize('e:\\Forex\\RoboForex MT5 Demo\\MQL5\\Libraries\\WorkWithPeople\\','Forex','0ndrei1960@gmail.com','WorkWithPeople');
      
         return(INIT_SUCCEEDED);
        }
      
      int OnCalculate(const int rates_total,
                      const int prev_calculated,
                      const datetime &time[],
                      const double &open[],
                      const double &high[],
                      const double &low[],
                      const double &close[],
                      const long &tick_volume[],
                      const long &volume[],
                      const int &spread[])
        {
         if(IsNewCandle()) 
           {
            ChartScreenShot(0,scr,800,600);
            Run::AddAttachment(fp scr);
            string body='Time: ' TimeToString(TimeLocal());
            int res=Run::DoWork('some subj',body,false);
            Print(body);
           }
         return(rates_total);  
        }
      
      

      指標(biāo)的完整代碼可以在所附 google_test2.mq5 文件中找到,它非常簡(jiǎn)單,因此不需要進(jìn)一步的討論。

      結(jié)論

      讓我們看看結(jié)果,我們分析了使用谷歌聯(lián)系人與合作伙伴進(jìn)行交互,以及將程序集與終端集成的方法,使用戶可以避免將文件夾與不必要的文件混淆。匯編代碼的效率也值得一提,我們對(duì)這一問題的關(guān)注不夠,但可以提供一系列活動(dòng)來解決這一問題:

      • 在谷歌中劃分授權(quán)和發(fā)送電子郵件的目標(biāo)。由計(jì)時(shí)器在單獨(dú)的線程中進(jìn)行授權(quán)。
      • 嘗試使用線程池發(fā)送電子郵件。
      • 使用異步工具對(duì)電子郵件附件進(jìn)行“大量”編碼。

      這并不意味著您應(yīng)該使用所有這些方法,但它們的使用可能會(huì)提高性能,并允許將生成的程序集作為單獨(dú)流程的一部分與MetaTrader一起單獨(dú)應(yīng)用。

      總之,讓我們回到使用MQL工具解決此任務(wù)的問題,有可能嗎?根據(jù)谷歌文檔,答案是肯定的,使用GET/POSTt請(qǐng)求可以獲得相同的結(jié)果,并提供適當(dāng)?shù)氖纠?。因此,可以使用常?guī)的WebRequest。這種方法的可行性仍然是一個(gè)爭(zhēng)論的問題,由于請(qǐng)求的數(shù)量非常多,因此很難編寫、調(diào)試和維護(hù)這樣的代碼。

      文章中使用的程序

       # 名稱
      類型
       描述
      1 google_test1.mq5
      腳本
      制作屏幕截圖并發(fā)送到多個(gè)地址的腳本。
      2
      google_test1.mq5 指標(biāo)
      在每個(gè)新燭形上發(fā)送電子郵件的示例指標(biāo)
      3 google.zip 檔案 程序集和測(cè)試控制臺(tái)應(yīng)用程序項(xiàng)目。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多