經常有這樣的事情發生,當你正在進行專案中某一部分的工作,裡面的東西處於一個比較雜亂的狀態,而你想轉到其他分支上進行一些工作。問題是,你不想只為了待會要回到這個工作點,就把做到一半的工作進行提交。解決這個問題的辦法就是 git stash 命令。git 在有 change 而未 commit 時,是無法切換到其他 branch,下圖為切換 branch 錯誤訊息,因此必須透過 stash 先把 change 暫存
星期一, 1月 30, 2017
[VSTS] Stash 暫存
Stash 介紹,擷取至繁體中文官網
星期三, 1月 25, 2017
管理 Windows 事件檢視器
之前聽過 DB 大師分享管理 Windows 事件檢視器,主要都是透過 Powershell + SQL Database Mail
最近因為有研究如何用 C# 讀取事件檢視器和建立服務相關,某天又剛好看到以前筆記,就試看看囉
利用 Windows Service 讀取 Error 事件並塞進 DB 內,再透過 SQL Database Mail 發信通知
- 利用 Powershell 把 Error 事件直接塞進 DB 內
- 利用 Powershell 把 Error 事件匯出 csv 檔案後,再利用 SSIS 抓進 DB
最近因為有研究如何用 C# 讀取事件檢視器和建立服務相關,某天又剛好看到以前筆記,就試看看囉
利用 Windows Service 讀取 Error 事件並塞進 DB 內,再透過 SQL Database Mail 發信通知
- 服務相關
- [C#] Windows Service
- [C#] Windows Service - 安裝後自動執行
- [.NET] 使用 BackgroundService 建立 Windows Service
- 事件檢視器相關
- [C#] EventLog
- SQL Server 驗證相關
- [SQL] SQL 驗證
星期二, 1月 24, 2017
[C#] new 關鍵字
閱讀該 [線上讀書會] 繼承 (Inheritance) new、virtual、override、abstract 影片筆記,主要是紀錄 new 的使用方式
Employ class
Manager class
Employ class
namespace ConsoleApplication1
{
public class Employee
{
public string Name { get; set; }
public decimal Salary { get; set; }
// virtual 和 overirde 關鍵字說明使用
public virtual void overrideShow()
{
Console.WriteLine($"{Name} 薪資為 {Salary}");
}
// new 關鍵字說明使用
public void NewShow()
{
Console.WriteLine($"{Name} => Employee.NewShow()");
}
}
}
Manager class
namespace ConsoleApplication1
{
public class Manager : Employee
{
public decimal Bonus = 5000;
public override void overrideShow()
{
// 利用 base 關鍵字呼叫 Employee.overrideShow()
base.overrideShow();
// override 後的 Manager 內容
Console.WriteLine($"{Name} 薪資為 {Salary} + 獎金 {Bonus} = {Salary + Bonus}");
}
public new void NewShow()
{
Console.WriteLine($"{Name} => Manager.NewShow()");
}
}
}
Program.csnamespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("====== Virtual、Override 關鍵字說明 =====");
Employee e1 = new Manager();
e1.Name = "管理人員";
e1.Salary = 50000;
e1.overrideShow();
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("===== New 關鍵字說明 =====");
Employee e2 = new Employee();
e2.Name = "Employee e2 = new Employee()";
e2.NewShow();
Console.WriteLine("----------");
Manager m2 = new Manager();
m2.Name = "Manager m2 = new Manager()";
m2.NewShow();
Console.WriteLine("----------");
Employee em2 = new Manager();
e2.Name = "Employee em2 = new Manager()";
e2.NewShow();
}
}
}
星期五, 1月 20, 2017
[SQL] SQL 驗證
實務上有需求,沒有透過 Windows 驗證來驗證使用者,改用 SQL 驗證,卻一直連不進 SQL Server,後來查才發現 instance 沒有改為 SQL Server 及 Windows 驗證,印象中是稱呼該選項為混合驗證,修改後重新啟動該 instance 就可以使用
MSDN 上的擷取內容
MSDN 上的擷取內容
SQL Server 驗證的缺點
- 如果某位使用者是擁有 Windows 登入和密碼的 Windows 網域使用者,則仍然必須提供其他 (SQL Server) 登入和密碼才能連接。 追蹤多個名稱和密碼對於許多使用者而言很困難。 此外,每次連接至資料庫就必須提供 SQL Server 認證可能會造成困擾。
- SQL Server 驗證無法使用 Kerberos 安全性通訊協定。
- Windows 提供了不適用於 SQL Server 登入的其他密碼原則。
SQL Server 驗證的優點
- 加密的 SQL Server 驗證登入密碼在連接時必須透過網路傳遞。 自動連接的某些應用程式會將密碼儲存在用戶端。 這些是額外的攻擊點。
- 可讓 SQL Server 支援需要 SQL Server 驗證的舊版應用程式以及協力廠商所提供的應用程式。
- 可讓 SQL Server 支援具有混合作業系統的環境,其中 Windows 網域無法驗證所有使用者。
- 可讓使用者從未知或未受信任的網域連接。 例如,既有客戶使用所指派 SQL Server 登入連接來接收訂單狀態的應用程式。
- 可讓 SQL Server 支援 Web 架構應用程式,其中使用者會建立自己的識別。
- 可讓軟體開發人員根據已知的現有 SQL Server 登入,使用複雜的權限階層來散發其應用程式。
- 參考資料
- 選擇驗證模式
星期二, 1月 17, 2017
[C#] Windows Service - 安裝後自動執行
根據這篇筆記 [C#] Windows Service 安裝 Windows Service 後,會發現該 Service 並沒有啟動,如下圖
在 PorjectInstaller 內註冊 AfterInatall Event,搭配 ServiceController 在安裝後自動啟動 Service
在 PorjectInstaller 內註冊 AfterInatall Event,搭配 ServiceController 在安裝後自動啟動 Service
using System.ServiceProcess;
namespace WalkthroughWindowsService
{
[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
InitializeComponent();
AfterInstall += (sender, e) =>
{
ServiceController sc = new ServiceController(serviceInstaller1.ServiceName);
if (sc != null)
sc.Start();
};
}
}
}
安裝後 Service 就會自動啟動啦星期二, 1月 10, 2017
[C#] 利用 Gmail 發信
學習使用 C# 利用 Gmail 來進行發信,該篇為練習範例
自訂控件 - MailAttach
自訂控件 - MailAttach
UserControl 內有 Label 和 Button 兩控件
- Label 顯示使用者傳送的檔案名稱
- Button 則是移除該附件
- RemoveAttachClick Event 則是方便外部了解使用者點選哪一個 Button
namespace GMail
{
public partial class MailAttach : UserControl
{
public string FileFullName { get; set; }
public string FileName { get; set; }
public event RemoveAttachEventHandler RemoveAttachClick;
public MailAttach(string fileFullName)
{
InitializeComponent();
FileFullName = fileFullName;
FileName = Path.GetFileName(fileFullName);
lblFileName.Text = FileName;
}
private void MailAttach_Load(object sender, EventArgs e)
{
}
public virtual void OnRemoveAttachClick()
{
if (RemoveAttachClick == null)
return;
RemoveAttachEventArgs e = new RemoveAttachEventArgs(FileName);
RemoveAttachClick(this, e);
}
private void btnRemoveAttach_Click(object sender, EventArgs e)
{
OnRemoveAttachClick();
}
}
public delegate void RemoveAttachEventHandler(object sender, RemoveAttachEventArgs e);
public class RemoveAttachEventArgs : EventArgs
{
private string _fileName;
public string FileName => _fileName;
public RemoveAttachEventArgs(string fileName)
{
_fileName = fileName;
}
}
}
主程式使用 WinForm 模擬介面,要透過 Gmail 來傳送 Email 含附件
實際測試
using System;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Windows.Forms;
namespace GMail
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private string _contentDefault { get; set; } = "該封為測試信";
private void Form1_Load(object sender, EventArgs e)
{
txtGmailPassword.PasswordChar = '*';
flpAttachment.FlowDirection = FlowDirection.TopDown;
flpAttachment.AutoScroll = true;
// 預設值
txtGmailAccount.Text = "OOXX@gmail.com";
txtGmailPassword.Text = "P@ssw0rd";
txtMailTo.Text = "123@gmail.com,456@gmail.com";
txtSubject.Text = "[C#] 利用 Gmail 發信";
txtBody.Text = _contentDefault;
}
private void btnAttachment_Click(object sender, EventArgs e)
{
OpenFileDialog fd = new OpenFileDialog();
fd.Multiselect = true;
fd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
if (fd.ShowDialog() != DialogResult.OK)
return;
foreach (string fileFullName in fd.FileNames)
{
// MailAttach 為自訂控件
MailAttach attach = new MailAttach(fileFullName);
attach.RemoveAttachClick += Attach_RemoveAttachClick; ;
flpAttachment.Controls.Add(attach);
}
}
private void Attach_RemoveAttachClick(object sender, RemoveAttachEventArgs e)
{
// 移除 UI 上 flpAttachment 內的檔案
MailAttach attach = flpAttachment.Controls.OfType<MailAttach>().Single(m => m.FileName == e.FileName);
flpAttachment.Controls.Remove(attach);
}
private void btnSend_Click(object sender, EventArgs e)
{
MailMessage mail = new MailMessage();
// 寄件人
mail.From = new MailAddress(txtGmailAccount.Text.Trim(), "系統發信");
// 收件人:
mail.To.Add(txtMailTo.Text.Trim());
mail.Subject = $"{txtSubject.Text.Trim()} - {DateTime.Now}";
mail.Body = txtBody.Text.Trim();
mail.IsBodyHtml = chkHTML.Checked;
mail.Priority = MailPriority.Normal;
Attachment attach;
foreach (MailAttach mailAttach in flpAttachment.Controls.OfType<MailAttach>())
{
attach = new Attachment(mailAttach.FileFullName);
attach.Name = mailAttach.FileName;
attach.NameEncoding = Encoding.GetEncoding("UTF-8");
mail.Attachments.Add(attach);
}
using (SmtpClient client = new SmtpClient("smtp.gmail.com", 587))
{
NetworkCredential credential = new NetworkCredential(txtGmailAccount.Text.Trim(), txtGmailPassword.Text.Trim());
client.EnableSsl = true;
client.Credentials = credential;
try
{
client.Send(mail);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
flpAttachment.Controls.Clear();
}
private void chkHTML_CheckedChanged(object sender, EventArgs e)
{
string content = string.Empty;
if (chkHTML.Checked == false)
content = _contentDefault;
else
content = "<table border=1><tr><td>ID</td><td>Name</td></tr><tr><td>40</td><td>該封為測試信</td></tr></table>";
txtBody.Text = content;
}
}
}
實際測試
- 延伸閱讀
- [SQL] Database Mail 搭配 Gmail 發信
- [C#] 自訂控制項內的事件 2
- 參考資料
- .NET 網路與I/O 技術手冊
- 如何使用Gmail幫我們發信
- [ASP.net / C#] .Net 完整的Mail寄信(Send Mail)功能
![[VSTS] Stash 暫存-1](https://c1.staticflickr.com/1/516/32451228392_899d185e6a.jpg)
![[C#] new 關鍵字-1](https://c1.staticflickr.com/1/514/32416824465_b8d93206cb_m.jpg)
![[C#] new 關鍵字-2](https://c1.staticflickr.com/1/445/32416824365_4d789b5b27.jpg)
![[SQL] SQL 驗證](https://c1.staticflickr.com/1/358/31981774640_d830c6355e_z.jpg)
![[C#] Windows Service - 安裝後自動執行-1](https://c1.staticflickr.com/1/275/31513638094_c488b85b75_z.jpg)
![[C#] Windows Service - 安裝後自動執行-2](https://c1.staticflickr.com/1/568/32356079705_5257640146_z.jpg)



