C# で踏み台サーバー経由で RDS for MySQLに接続する方法

概要

ローカル開発マシンから、C#を使用してSSHでBastion(踏み台)サーバーに接続し、ポートフォワードしてRDS for MySQLに接続してデータを取得する方法について説明します。
ポートフォワードの部分の設定が理解できなくて設定に迷って手間取ったのでした。
ポートフォワード元と先に何を設定すべきか。。。

設定手順

  1. Visual Studio で「プロジェクト」 → 「Nugetパッケージの管理」を選択する。
  2. 「mysql.data」と「ssh.net」をインストールする。
    • image.png
    • image.png
  3. SSHでAWSのBastionサーバー(踏み台)に接続し、ポートフォワードでRDS fro MySQL に接続する。
var pkFile = new PrivateKeyFile(@"E:\aws.pem", "");
var connBuilder = new MySqlConnectionStringBuilder
{
    AllowBatch = true,
    Server = "127.0.0.1",
    Port = 3306,
    UserID = "hoge",
    Password = "foo",
    Database = "fuga"
};
using (var client = new SshClient("54.65.***.***", 22, "ec2-user", pkFile))
{
    client.Connect();
    var forward = new ForwardedPortLocal("127.0.0.1", 3306, "rds-mysql.****.ap-northeast-1.rds.amazonaws.com", 3306);
    client.AddForwardedPort(forward);
    forward.Start();
    using (var connection = new MySqlConnection(connBuilder.ConnectionString))
    {
        connection.Open();
        using (var com = new MySqlCommand("SELECT * FROM t_user limit 1", connection))
        {
            com.CommandType = CommandType.Text;
            var ds = new DataSet();
            var da = new MySqlDataAdapter(com);
            da.Fill(ds);
            foreach (DataRow drow in ds.Tables[0].Rows)
            {
                Debug.WriteLine("From MySql: " + drow[1].ToString());
            }
        }
        forward.Stop();
    }
}

C# でSSMS の接続ダイアログを使用する方法

C# で、SQL Server Management Studio の接続ダイアログを使用する方法について説明します。

接続ダイアログについてのドキュメントは、<<ここ>>で公開されています。

C#アプリケーションから、SSMS 接続ダイアログ(CoonectionDialog)を使用するには、次のスニペットを使用します。

Microsoft.SqlServer.Management.UI.ConnectionDlg

インスタンス化

ConnectionDialog dlg = new Microsoft.SqlServer.Management.UI.ConnectionDlg.ConnectionDialog();

次にGUI部分には、次のスニペットを使用します。

Microsoft.SqlServer.Management.Smo.RegSvrEnum

インスタンスと利用方法。

UIConnectionInfo connInfo = new Microsoft.SqlServer.Management.Smo.RegSvrEnum.UIConnectionInfo { ApplicationName = “My App” };

IDbConnection conn;
dlg.AddServer(new Microsoft.SqlServer.Management.UI.ConnectionDlg.SqlServerType());
dlg.Text = “Connect to My Database”;

DialogResult dr = dlg.ShowDialogValidateConnection(this, ref connInfo, out conn);
if (DialogResult.OK == dr)
{
   m_strConnString = conn.ConnectionString + “;Pooling=TRUE”;
   if(false == m_strConnString.Contains(“Database=”))
      m_strConnString += “;Database=MyDb”;
   bRC = true;
}
else
{
   bRC = false;
}

コンパイルするには、RegSvrEnum と ManagementControlsへの参照が必要です。

  • Microsoft.SqlServer.Management.Controls
  • Microsoft.SqlServer.Management.UserSettings
  • Microsoft.SqlServer.RegSvrEnum
  • SqlWorkbbench.Interfaces

C# 6.0 新機能まとめ from de:code2015

C# 6.0が正式リリースされたので、どんな機能が実装されたのかを勉強してみたいと思います。この投稿は、Channel 9で公開されてるde:code 2015のセッション「C# 6.0新機能」を元にしたものです。

C# 6.0 の新機能概要

非常に大きな言語変更はないが、数多く(10数個)の新機能が実装されています。
新機能の大部分は、開発者のコード量を削減し開発生産を高めることを目標としています。

  • オーバーロード解決の向上
  • 例外フィルター
  • インデックス初期化子
  • ラムダ式本体によるメンバーの記述
  • 自動実装プロパティの機能強化
  • using static
  • Nameof 演算子
  • 文字列補間
  • Null 条件演算子
  • パラメーターを持たない構造体

自動実装プロパティ

getterのみのプロパティを実装できるようになりました。

public int X { get; }
public int Y { get; }

using static

using staticを使用するとメソッドの呼び出しを単純化することができます。

コード記述量を減らすことができます。

using static System.Console;
using static System.Math;
Console.WriteLine(Math.Sqrt(3*3+4*4));
WriteLine(Sqrt(3*3+4*4));

文字列補間

{0}や{1}のところに直接変数を指定することができるようになりました。

return String.Format("({0}, {1})",X,Y);
return $"({X}, {Y})"

ラムダ式によるメソッド本体記述

従来の書き方

public override string ToString()
{
  return $"({X}, {Y})";
}

書き換えると…

public override string ToString()=>$"({X}, {Y})";

ラムダ式によるプロパティの記述

従来の書き方

public double Dist
{
  get { return Sqrt(X*X+Y*Y);}
}

書き換えると…

public double Dist => Sqrt(X*X+Y*Y);

インデックス初期化子

従来の書き方

var numbers = new Dictionary
{
  {1, "one"},
  {2, "two"},
  {3, "three"}
};

書き換えると…

var numbers = new Dictionary
{
  [1] = "one",
  [2] = "two",
  [3] = "three"
};

Null条件演算子

nullチェックをするための演算子です。nullであればnullを入れて、nullじゃなければ値を入れる。

int? count = person?.Count();

nameof演算子

定義した変数の名前を返す場合の処理を効率化したものです。ArgumentNullExceptionに従来は文字列を指定していたが、それでは変数名をリファクタリングしたときに変更がもれることがあった。それを防ぐために変数名を返す演算子が追加された。

public Point Add(Point point)
{
  if(point==null)
  {
    throw new ArgumentNullException(nameof(point));
  }
}

参考

HttpClientでBasic認証をする方法

System.NET.Http にある HttpClient を使って、Basic認証をする方法を調べました。
単純にする方法は検索すると、類似サンプルコードが複数でてくるのですが、
恰好良く見えないのです。
もっと綺麗な方法があるに違いないと思ったのですが、そんなことは無かったて話。

Basic認証をする方法(推奨)

var httpClient = new HttpClient();
var byteArray = Encoding.ASCII.GetBytes(string.Format("{0}:{1}", username, password));
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));

Basic認証をする方法その2(非推奨)

var credential = new BasicCredentialsProvider();
credential.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
var auth = new BasicAuthCache();
auth.put(targetHost, new BasicScheme());
var context = HttpClientContext.create();
context.setCredentialsProvider(credential);
context.setAuthCache(auth);

エンコードとかのコードがなくなって、スマート(行数増えてるけど…)に見えなくもない。
でも、この方法の問題点は、
認証をするために、プリ認証、本認証と2回通信が発生してしまうこと。
認証は成功するんですけどね…。

参考

HttpClientのBaseAddressを使う方法

System.Net.HttpにあるHttpClientのBaseAddressの使い方がわからなかったので調べてみた。

HttpClientの使用例として、次のサンプルのようにGetAsyncなどの直接URLを記述する例をよく見ます。

using System.Net.Http;
var httpClient = new HttpClient();
var response = await httpClient.GetAsync("http://requestb.in/10v5oew1");

一方で、インテリセンスを見てると、BaseAddressなんてプロパティがあります。
どうやって使い分けるのかがわからなかったので調べてみました。

using System.Net.Http;
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://requestb.in/10v5oew1/"); // こいつは何もの?

調べるのに使用したのは、次のコード。

var baseUri = "";
var getUri = "";
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(baseUri);
var response = await httpClient.GetAsync(getUri);

「baseUri」と「getUri」にいろんなパターンを当てはめて動作を調べてみました。

image

「getUri」にフルパスを指定した場合は、「baseUri」にどのようなUriを指定していも、「getUri」で指定したUriにリクエストをする。上書きをする動き。
「baseUri」が「http: //yahoo.co.jp」で、「getUri」が「http: //google.com」と、完全に異なるドメインを指定したとしても、「getUri」の指定が優先される。

「baseUri」の終わりがスラッシュ(「http: //yahoo.co.jp/foo/」)で、「getUri」の始まりがスラッシュでない文字列(「hoge/foo?bar=1」みたいなの)を指定した場合、単純に文字列結合したUrl(「http: //yahoo.co.jp/foo/hoge/foo?bar=1」)にリクエストする。

それ以外のパターンでは、「baseUri」のホストドメイン+「getUri」が結合されたUriにリクエストされる。

結論

HttpClientのBaseAddressを有効活用したいのなら、

– BaseAddressは、スラッシュで終わる
– GetAsyncなどのメソッドでは、スラッシュではじめない

ことが重要であることがわかりました。