ASP.NET MVC Windowsフォームからのリクエスト

概要

クライアント側がブラウザではなく、Windowsフォームを使用する例

GET

※MVCプロジェクト
namespace MyMVC.Controllers
{
 クライアントからのリクエストを制御
 public class TestController : Controller
 {
  public string Do(string prm)
  {
   ActionResult型でなく、文字列型を返す
   return prm;
  }
 }
}

クライアントからのパラメータの振り分け先設定
namespace MyMVC
{
 public class RouteConfig
 {
  public static void RegisterRoutes(RouteCollection routes)
  {
   routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
   
   routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{prm}",
    defaults: new { controller = "Test", action = "Do", prm = UrlParameter.Optional }
   );
  }
 }
}

※Windowsフォームプロジェクト
WebRequest作成
var req = WebRequest.Create(@"http://localhost:12345/Test/Do/AAA");
本来はブラウザで指定するURLをWebRequestに設定
(AAAはパラメータ)
WebResponse作成
var res = req.GetResponse();
応答データ受信の為のStreamを取得
Stream st = res.GetResponseStream();
文字コード指定、StreamReader作成
StreamReader sr = new StreamReader(st, Encoding.UTF8);
データ受信
string htmlSource = sr.ReadToEnd();
MessageBox.Show(htmlSource);
→AAA
終了処理
sr.Close();
st.Close();
res.Close();

POST

WebRequestの作成
WebRequest req = WebRequest.Create("http://localhost:12345/Test/Do");
本来はブラウザで指定するURLをWebRequestに設定
POST送信する文字列をバイト型配列に変換
byte[] postDataBytes = Encoding.ASCII.GetBytes("AAA");

メソッドにPOSTを指定
req.Method = "POST";
ContentTypeを"application/x-www-form-urlencoded"に
req.ContentType = "application/x-www-form-urlencoded";
POST送信するデータの長さを指定
req.ContentLength = postDataBytes.Length;
POST送信の為のStreamを取得
Stream reqStream = req.GetRequestStream();
送信するデータ書き込み
reqStream.Write(postDataBytes, 0, postDataBytes.Length);
reqStream.Close();
リクエストメッセージ取得
WebResponse res = req.GetResponse();
↑ 受信データからStreamを取得
Stream resStream = res.GetResponseStream();
読み込み
StreamReader sr = new StreamReader(resStream, Encoding.GetEncoding("shift_jis");
MessageBox.Show(sr.ReadToEnd());
→AAA
終了処理
sr.Close();

※MVCプロジェクト
namespace MyMVC.Controllers
{ 
 クライアントからのリクエストを制御
 public class TestController : Controller
 {
  [HttpPost]
  public string Do()
  {
   Request.InputStream.Position = 0;
   using (StreamReader reader = new StreamReader(Request.InputStream, Encoding.UTF8))
   {
    string output = reader.ReadToEnd();
    ActionResult型でなく、文字列型を返す
    return output;
   }
  }
 }
}

WEBアクセス方法(C#)

WebClientクラス

DownloadFile

using System.Net;
指定のURLデータを取得&保存
new WebClient().DownloadFile(address: @"http://office-yone.com", fileName: @"office-yone.html");

OpenRead

using System.Net;
using System.IO;
指定のURLデータを取得
Stream st = new WebClient().OpenRead("http://office-yone.com");
var sr = new StreamReader(st, Encoding.GetEncoding("Shift_JIS"));
string html = sr.ReadToEnd();
sr.Close();
st.Close();
MessageBox.Show(html);

DownloadData

using System.Net;
指定のURLデータを取得
byte[] data = new WebClient().DownloadData("http://office-yone.com");
string html = Encoding.GetEncoding("Shift_JIS").GetString(data);
MessageBox.Show(html);

プロキシ利用

using System.Net;
var client = new WebClient();
プロキシ利用
client.Proxy = WebRequest.DefaultWebProxy;
プロキシ指定
client.Proxy = new WebProxy("http:~:8080");
プロキシ未使用
client.Proxy = null;
client.~

WebRequest・WebResponseクラス

GET

using System.Net;
using System.IO;

リクエスト作成
var req = WebRequest.Create(@"http://office-yone.com");
リクエスト送信&レスポンス取得
var res = req.GetResponse();
↑ 受信データからStreamを取得
Stream resStream = res.GetResponseStream();
読み込み
var reader = new StreamReader(st, Encoding.GetEncoding("Shift_JIS"));
string html = reader.ReadToEnd();
reader.Close();
st.Close();

POST

using System.Net;
using System.IO;

WebRequestの作成
var req = WebRequest.Create("http://~;");

POST送信する文字列をバイト型配列に変換
byte[] postDataBytes = Encoding.ASCII.GetBytes("AAA");

メソッドにPOSTを指定
req.Method = "POST";

ContentTypeを"application/x-www-form-urlencoded"に
req.ContentType = "application/x-www-form-urlencoded";

POST送信するデータの長さを指定
req.ContentLength = postDataBytes.Length;
POST送信の為のStreamを取得
Stream reqStream = req.GetRequestStream();

送信するデータ書き込み
reqStream.Write(postDataBytes, 0, postDataBytes.Length);
reqStream.Close();

リクエストメッセージ取得
var res = req.GetResponse();
↑ 受信データからStreamを取得
Stream resStream = res.GetResponseStream();

読み込み
StreamReader sr = new StreamReader(resStream, Encoding.GetEncoding("shift_jis"));
string html = reader.ReadToEnd();
reader.Close();
st.Close();

クッキー送受信

using System.Net;
WebRequestの作成
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(@"http:localhost:51496/Mvc/Do/AAA");
CookieContainerプロパティを設定する
req.CookieContainer = new CookieContainer();
要求元のURIに関連したCookieを追加し、要求に使用する
req.CookieContainer.Add(_cookie.GetCookies(req.RequestUri));
サーバーからの応答を受信するためのWebResponseを取得
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
受信したCookieのコレクションを取得する
CookieCollection cookies = req.CookieContainer.GetCookies(req.RequestUri);
Cookie名と値を列挙する
foreach (Cookie cook in cookies)
 Console.WriteLine("{0}={1}", cook.Name, cook.Value);
 →name=test
 →value=1
取得したCookieを保存
_cookie.Add(cookies);
応答データを受信するためのStreamを取得
Stream st = res.GetResponseStream();
StreamReader reader = new StreamReader(st, Encoding.GetEncoding("shift_jis"));
受信して表示
string html = reader.ReadToEnd();
reader.Close();

namespace MyMVC.Controllers
{
 public class MvcController : Controller
 {
  public string Do(string prm)
  {
  string val = Response.Cookies["name"].Value;
  
  Response.Cookies["name"].Value = HttpUtility.UrlEncode("test");
  Response.Cookies["name"].Expires = DateTime.Now.AddMinutes(60);
  Response.Cookies["value"].Value = "1";
  Response.Cookies["value"].Expires = DateTime.Now.AddMinutes(60);
  
  削除時
  Response.Cookies.Remove("name");
  
  return prm;
 }
 }
}

HttpClient

static void Main(string[] args)
{
 非同期で実行
 string result = myFunc().Result;
}
private static async Task myFunc()
{
 return = await new HttpClient().GetStringAsync(@"http://office-yone.com");
}

プログラム言語 エンコード・デコード処理

エンコードとは

符号化
文字に対してコンピュータで扱う文字コード=コード(数値)を割り振る事
テキストエディタで文字データを作成・保存した際、
OS毎の割り振られる文字コードは以下の通り。
・Windows:Shift_JIS
・UNIX系:EUC
・Mac:Unicode
テキストエディタの機能によって保存時の文字コードを変更する事は可能
OSに関わらずUTF-8が国際的に標準化されつつある。
特にHTML5では推奨される。
漢字をUTF-8で保存すると容量が増えるという問題点あり
XMLでは、XML宣言でエンコードの種類を明示的に表記する
<?xml version="1.0" encoding="Shift_JIS"?>
<a>~</a>

割り振られた文字コードを解析して読み込む事をデコードと言う。
割り振られた文字コードと違う文字コードで読み込んだ場合、文字化けする。

読込

string[] s;
s = File.ReadAllLines(@"D:\~txt", Encoding.Default);
s = File.ReadAllLines(@"D:\~.txt", Encoding.GetEncoding(name: "Shift_JIS"));
s = File.ReadAllLines(@"D:\~.txt", Encoding.Unicode);
s = File.ReadAllLines(@"D:\~.txt", Encoding.UTF8);

書込

File.WriteAllLines(@"D:\~txt", @"内容", Encoding.Default);
File.WriteAllLines(@"D:\~.txt", @"内容", Encoding.GetEncoding(name: "Shift_JIS"));
File.WriteAllLines(@"D:\~.txt", @"内容", Encoding.Unicode);
File.WriteAllLines(@"D:\~.txt", @"内容", Encoding.UTF8);

BASE64エンコード・デコード

BASE64とは?
バイナリデータ→テキストデータ
への変換方式
英数字のみで構成される
暗号ではない

import java.io.IOException;
import org.apache.commons.codec.binary.Base64;

public class base64test {
 public static void main(String[] args) {
  try{
   String after = encodeBase64("~");
  }
  catch ( ~ ){
   ~
  }

 }
 
 public static String encodeBase64(String before) throws IOException {
  byte[] out = Base64.encodeBase64(before.getBytes());
  return new String(out, "shift_jis");
 }
}

Sub main
 after = encode("~")
 after = decode("~")
End Sub

'Base64文字列にエンコードする
Public Function encode(val As String) As String

 Dim objBase64 As Object
 Dim b() As Byte
 b = stringToByte(val)
 
 'Msxml2.DOMDocumentオブジェクト = XML操作オブジェクト
 Set objBase64 = CreateObject("MSXML2.DOMDocument").createElement("b64")
 objBase64.DataType = "bin.base64"
 objBase64.nodeTypedValue = b
 encode = objBase64.text
 
 Set objBase64 = Nothing

End Function

'Base64文字列をデコードする
Public Function decode(val As String) As String
 Dim objBase64 As Object
 'Msxml2.DOMDocumentオブジェクト = XML操作オブジェクト
 Set objBase64 = CreateObject("MSXML2.DOMDocument").createElement("b64")
 objBase64.DataType = "bin.base64"
 objBase64.text = val
 
 Dim b() As Byte
 b = objBase64.nodeTypedValue
 decode = byteToString(b)
 
 Set objBase64 = Nothing

End Function

'文字列バイト列に変換する
Public Function stringToByte(ByVal strData As String) As Byte()

 Dim objStream As Object
 Set objStream = CreateObject("ADODB.Stream")
 
 objStream.Open
 objStream.Type = adTypeText
 objStream.Charset = "utf-8"
 objStream.WriteText strData
 
 objStream.Position = 0
 objStream.Type = adTypeBinary
 objStream.Position = 3
 stringToByte = objStream.Read
 
 objStream.Close
 Set objStream = Nothing
 
End Function

プログラム言語 XML操作

作成

文字列指定

using System.Xml;

const string url = "http://example.com/";
var doc = new XmlDocument();

親要素・属性
var root = doc.CreateElement("root", url);
var att = doc.CreateAttribute("att");
att.AppendChild(doc.CreateTextNode("sample"));
root.Attributes.Append(att);

子要素
var child1 = doc.CreateElement("child1", url);
child1.AppendChild(doc.CreateTextNode("sample1"));
root.AppendChild(child1);

var child2 = doc.CreateElement("child2", url);
child2.AppendChild(doc.CreateTextNode("sample2"));
root.AppendChild(child2);

doc.AppendChild(root);

Console.WriteLine(doc.OuterXml());

親要素・属性・子要素をまとめて構築
doc.LoadXml("<root att='sample' xmlns='http://example.com/'><child1>sample</child1><child2>sample</child2></root>");

Console.WriteLine(doc.OuterXml());

結果
<root att="sample" xmlns="http://example.com/">
 <child1>sample</child1>
 <child2>sample</child2>
</root>

using System.Xml.Linq;

var doc = new XDocument();
XNamespace name = "http://example.com/";
var root = new XElement(name + "root");
var attRoot = new XAttribute("attRoot", "value");
var elm1 = new XElement(name: "elm1", content: "value1");
var elm2 = new XElement(name: "elm2", content: "value2");
var attElm = new XAttribute("attElm", "value");

root.Add(elm1);
root.Add(elm2);
elm2.Add(attElm);
root.Add(attRoot);
doc.Add(root);

Console.WriteLine(doc.ToString());

XNamespace name = "http://example.com/";
var root = new XElement(
 name + "root", new XAttribute("att", "valueAtt"),
 new XElement("elm1", "value1"),
 new XElement("elm2", new XAttribute("attElm", "value"), "value2"));

Console.WriteLine(root.ToString());

結果
<root attRoot="value" xmlns="http://example.com/" >
 <elm1>value</elm1>
 <elm2 attElm="value">value</elm2>
</root>

文字列→XML変換

var doc = XDocument.Parse("<root xmlns='http://office-yone.com/'><a>システム開発</a><b>ホームページ作成</b></root>");

結果
Console.WriteLine(doc.ToString());
<root xmlns='http://office-yone.com/'>
 <a>システム開発</a>
 <b>ホームページ作成</b>
</root>

読取

値で検索

var doc = XDocument.Parse("<root xmlns='http://office-yone.com/'><a>システム開発</a><b type="web">ホームページ作成</b><c><d>インフラ構築</d></c></root>");

XNamespace name = "http://office-yone.com/";
int count = doc.Descendants(name + "a").Count();
count:1

int count = doc.Descendants(name + "b").Where( x => x.Value == "ホームページ作成").Count();
count:1

int count = doc.Descendants(name + "b").Where( x => x.Attribute("type").Value == "web").Count();


<root xmlns='http://office-yone.com/'>
 <a>システム開発</a>
 <b type="web">ホームページ作成</b>
 <c>
  <d>インフラ構築</d>
 </c>
</root>

要素名で検索

var doc = XDocument.Parse("<a><b><c>WordPress</c></b></a>");
string val = doc.Element("a").Element("b").Element("c").Value;
val:WordPress

<a>
 <b>
  <c>WordPress</c>
 </b>
</a>

var doc = XDocument.Parse("<a><b><c>C#</c></b><b><c>Java</c></b></a>");
foreach (var elm in doc.Element("a").Elements("b").Elements("c"))
{
 Console.WriteLine(elm.Value);
};
→C# Java

<a>
 <b>
  <c>C#</c>
 </b>
 <b>
  <c>Java</c>
 </b>
</a>

ASP.NET Webフォーム Ajax利用

Ajaxとは?

Asynchronous JavaScript XML
WEBページの一部を変更したい時に、
ページ全体を更新せずに一部分だけを更新する技術
XMLHttpRequest(ブラウザに組み込まれたJavaScript組み込みクラス)クラスにおける非同期通信によってなされる。
非同期通信を行うとFormLoadイベント等は発生するがページ全体の更新は行われないので、ブラウザの「戻る」ボタン等も有効にならない。

Ajax通信時のロード処理

Ajax通信時もPostBackは発生する(=Page_Loadイベントが発生する)。
Page.IsPostBack = True
ただしクライアント側において全画面の再描画は行われない。

通常
Buttonクリック→サーバー処理→全画面再描画
Ajax通信時
Buttonクリック→サーバー処理→指定部分再描画

※~.aspx
<script>
 function myFunc() {
  window.alert("LoadOK");
 }
</script>
<body onload="myFunc();">
 <asp:ScriptManager ID="manager" runat="server"></asp:ScriptManager>
 <asp:UpdatePanel ID="myUpdate" runat="server">
  <ContentTemplate>
   <asp:TextBox ID="myText" runat="server"></asp:TextBox><br />
  </ContentTemplate>   
  <Triggers>
   <asp:AsyncPostBackTrigger ControlID="myButton" EventName="Click" />
  </Triggers>
 </asp:UpdatePanel>
 <asp:Button ID="myButton" runat="server" Text="Button" onclick="myButton_Click" />
</body>

※~.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
 if (!Page.IsPostBack)
 {
  this.myText.Text = "NoPostBack";
 }
 else
 {
  this.myText.Text = "PostBack";
 }
}
protected void myButton_Click(object sender, EventArgs e)
{
 this.myText.Text = "Ajax";
}

【初回ロード時】
サーバー:
Page_Loadイベント

Page.IsPostBack = False なので、this.myText.Text = "NoPostBack";

クライアント:
画面描画

onloadイベント

fncInitSpread()実行

【ボタンクリック時】
サーバー:
Page_Loadイベント

Page.IsPostBack = True なので、this.myText.Text = "PostBack";

クライアント:
UpdatePanel内のみ描画

※onloadイベントは発生しない

AJAX Extensionsコントロール

ASP.NETでは「ASP.NET AJAX Extensionsコントロール」を配置する事でAjaxを利用できる。
ASP.NET AJAX Extensionsコントロールには、
・UpdatePanel
等があり、
UpdatePanel上のデータを非同期でページ全体のポストバックを発生させずに更新できる。
非同期ポストバックと呼ばれる画面一部のポストバックは発生する

ScriptManagerコントロール

UpdatePanel等のAjax Extensionsコントロールを使用する際、
先頭に配置する事で配下のコントロールの非同期通信を可能にする。

UpdatePanelコントロール

※~.aspx
<form id="myForm" runat="server">
 ※スクリプトマネージャー:AJAXを有効にする
 <asp:ScriptManager ID="myScriptManager" runat="server"></asp:ScriptManager>
 
 ※Updateパネル:パネル内のコントロールについて非同期通信を行う
 <asp:UpdatePanel ID="myUpdatePanel" runat="server" >
  <ContentTemplate>
   <asp:Label ID="myLabel" runat="server" Text=""></asp:Label>
  </ContentTemplate>
  
  ※↓のイベントをトリガーとして↑パネル内のみ非同期通信を行う
  <Triggers>
   <asp:AsyncPostBackTrigger ControlID="myButton" EventName="Click" />
  </Triggers>
  
 </asp:UpdatePanel>
 ※↓ボタン押下イベントハンドラをaspx.csファイルに記述
 <asp:Button ID="myButton" runat="server"
   Text="非同期更新" OnClick="myButton_Click" />
</form>

※~.aspx.cs
public partial class MyForm : System.Web.UI.Page
{

 protected void myButton_Click(object sender, EventArgs e)
 {
  // 非同期通信処理
  this.myLabel.Text = this.myTextBox.Text;
  
  ※複数のUpdateパネルを使用している場合に、
  規定のトリガー以外で非同期通信を実行する場合

  hisUpdatePanel.Update();
 }
}

UpdateProgressコントロール

※~.aspx
<form id="myForm" runat="server">
 <asp:ScriptManager ID="myScriptManager" runat="server"></asp:ScriptManager>
 
 <asp:UpdatePanel ID="myUpdatePanel" runat="server">
  <ContentTemplate>
   <asp:Label ID="myLabel" runat="server"
    Text="処理前"></asp:Label><br />
   <asp:Button ID="myButton" runat="server"
    Text="非同期更新" OnClick="myButton_Click" /><br />
  </ContentTemplate>
 </asp:UpdatePanel>
 
 // ↑の非同期処理中のみ表示される
 <asp:UpdateProgress ID="myUpdateProgress" runat="server"
   AssociatedUpdatePanelID="myUpdatePanel">
  <ProgressTemplate>
   <asp:Image ID="myLoading" runat="server"
    // myUpdatePanelが通信中のみ表示される。
    ImageUrl="(gif画像パス)" />
    しばらくお待ちください。
  </ProgressTemplate>
 </asp:UpdateProgress>
</form>

※~.aspx.cs
public partial class MyForm : System.Web.UI.Page
{

 protected void myButton_Click(object sender, EventArgs e)
 {
  // 非同期通信処理
  ~
  this.myLabel.Text = "完了";
 }
}

非同期通信後のスクリプト埋め込み

Updateパネル内の非同期通信処理発生時にサーバーサイドからクライアントサイドへスクリプトを埋め込み/実行させる場合
(非同期通信中は通常のポストバックが発生しない為、Page.~の埋め込みは使用できない)
※UpdatePanel内に配置したコントロール(ボタン等)のイベント内に書く事
ScriptManager.RegisterClientScriptBlock(
 ページ,
 スクリプトを埋め込むコントロールの型,
 キー,
 スクリプト文,
 <script>タグを追加するか否か?);
ScriptManager.RegisterClientScriptBlock(
 this,
 this.GetType(),
 "myKey",
 "fnMyfunc();",
 true);
→<script>fnMyFunc();</script>
ScriptManager.RegisterClientScriptBlock(
 this,
 this.GetType(),
 "myKey",
 "<script>fnMyFunc();</script>",
 false);
→<script>fnMyFunc();</script>

参考:通常ポストバック時のスクリプト埋め込み

画面の表示前にスクリプトを実行する
Page.RegisterClientScriptBlock(型, キー, スクリプト文)
Page.RegisterClientScriptBlock(this.GetType(), "client", "<script> alert('前') <" + "/script>");
画面の表示後にスクリプトを実行する
Page.RegisterStartupScript(型, キー, スクリプト文)
Page.RegisterStartupScript(this.GetType(), "startup", "<script> alert('後') <" + "/script>");

AJAX Control Toolkit

ToolkitScriptManagerコントロール

ScriptManagerコントロールとほぼ同等の機能を持つ
ToolkitScriptManager.CombineScriptsプロパティ=True により、
Ajaxに関わる重複するJavaScriptファイルをダウンロードせずに済ませられる。

UpdatePanelAnimationExtenderコントロール

<ajaxToolkit:UpdatePanelAnimationExtender
 ID="~"
 runat="server"
 
 Ajax通信が実行されるコントロールを指定。
 TargetControlID="~">
 
 対象コントロールの通信終了後に、指定のアニメーションを実行する。
 <Animations>
  更新完了時のアニメーションを定義
  <OnUpdated>
   <Sequence>
    ラベルの背景色を#008800(緑)から#FFFFFF(白)に変更
    <Color AnimationTarget="lblAsync"
     PropertyKey="backgroundColor"
     StartValue="#008800" EndValue="#FFFFFF" />
    
    JavaScript関数を実行
    <ScriptAction Script="myJsFunc();" />
   </Sequence>
  </OnUpdated>
 </Animations>
</ajaxToolkit:UpdatePanelAnimationExtender>

Microsoft AJAX Library

クライアントサイド技術
・Sys.WebForms.PageRequestManagerクラス
UpdatePanelコントロールによって発生した非同期通信(部分更新)を管理
サーバーサイドのUpdatePanelコントロールの機能を拡張する技術
JavaScriptから利用する。
・Sys.Applicationクラス
ページ全体に関わる部分を管理

<script type="text/javascript">
 function pageLoad()
 {
  // PageRequestManagerインスタンスの作成(newではない)
  var mng = Sys.WebForms.PageRequestManager.getInstance();
  
  // 非同期通信の開始と同時に実行される。
  mng.add_initializeRequest(
   function (sender, args) {
    $get('lblStatus').innerHTML =
      args.get_postBackElement().id
        + 'から非同期ポストバックが実行されました。';
   }
  );
  
  // 非同期通信の終了と同時に実行される。
  mng.add_endRequest(
   function (sender, args) {
    $get('lblStatus').innerHTML = '';
   }
  );
 }
</script>