fc2ブログ

記事一覧

WCFサービスでPOSTまたはGETでJSONを送受信する方法 | asp.net


今回は asp.net の WCF サービス で GET と POST のそれぞれで JSON を送受信する方法について覚え書きします。前回の記事でも触れましたが、WCF サービスでは従来のWEB サービスを手軽に実装できるだけでなく、VB からはもちろんのこと、aspx ページ等の JavaScript から呼び出したり、別のサイトから URL 経由で呼び出すことも簡単にでき、GET や POST にも対応しています。さらにはJSON文字列を送受信することにより様々な REST API にも対応することが可能です。


前提条件
・Windows 7 Professional 以降 / Windows Server 2008 R2 以降
・Visual Studio 2010 Professional 以降
・VB.NET
・.Net Framework 4.0 以降



1.JSONの変換方法

まず、JSON 文字列を送受信するにあたり、そのデータを加工したり追加したりしなければなりませんが、文字列のままだと操作しづらいですので、一度クラスのインスタンスに保持して再度 JSON に戻してから戻り値にセットしてあげると便利です。
以前の記事にて JSON 文字列とオブジェクトの相互の変換方法についてご紹介しておりますので、以下のリンク先をご確認くださいませ。

JSON形式の文字列データをクラスに変換する方法 -デシリアライズ-
クラスをJSON形式の文字列データをに変換する方法 -シリアライズ-



2.GETでのJSONの送受信方法

前回の記事でも GET の WCF サービスの作成方法について触れましたが、今回は JSON での送受信方法について追加します。
今回は2つの関数を用意しました。どちらも引数は JSON の文字列で、WebGet 属性に Request / Response のフォーマットを JSON に設定しています。戻り値のみが文字列と System.ServiceModel.Channels.Message で異なっています。

TestGetService.svc.vb
Option Explicit On
Option Strict On

Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports System.ServiceModel.Activation
Imports System.ServiceModel.Web
Imports BaseLibrary.Library
Imports AspNetTest.ViewModels

<ServiceContract(Namespace:="")>
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)>
Public Class TestGetService

<OperationContract()>
<WebGet(RequestFormat:=WebMessageFormat.Json,
ResponseFormat:=WebMessageFormat.Json)>
Public Function TestGetFunction1(ByVal json As String) As String

Dim entity As Customer = JsonUtility.GetObject(Of Customer)(json)

'セッションを保存する
WcfService.Common.SetSession()

'クッキーを設定する
WcfService.Common.SetCookie()

Dim ret As Customer = entity
Return JsonUtility.GetJson(ret)

End Function

<OperationContract()>
<WebGet(RequestFormat:=WebMessageFormat.Json,
ResponseFormat:=WebMessageFormat.Json)>
Public Function TestGetFunction2(ByVal json As String) As Message

Dim entity As Customer = JsonUtility.GetObject(Of Customer)(json)

'セッションを保存する
WcfService.Common.SetSession()

'クッキーを設定する
WcfService.Common.SetCookie()

Dim ret As Customer = entity
Return WcfService.Common.GetJsonResponse(Of Customer)(ret)

End Function

End Class

※JsonUtility については JSON のデシリアライズシリアライズにてご紹介しています。
※セッションを保存したりクッキーに書き込みする共通関数は後述します。



3.GETの実行結果

実行結果をブラウザで確認します。(URL の指定方法は前回の記事で覚え書きしました。)
関数に設定した文字列通りの値を戻り値にもセットしていますので、引数と戻り値の値が同じになるはずですが、文字列で返した値には {"d":" JSON文字列 "} という形式になっています。これは Microsoft の仕様でして、戻り値を System.ServiceModel.Channels.Message で返すことで回避が可能です。

aspnet_wcfservice_04.png



4.POSTでのJSONの送受信方法

GET と同様に2つの関数を用意しました。どちらも引数は JSON の文字列ですが、関数自体の引数で取得することはできません。RequestContext.RequestMessage で POST のデータが取得できますが JSON 文字列が XML 文字列になっています。これも Microsoft の仕様のようで、強制的に XML ヘッダーを付与して XML で読み取りを行っています。また、関数には WebInvoke 属性を設定し、Request / Response のフォーマットを JSON に設定しています。戻り値のみが文字列と System.ServiceModel.Channels.Message で異なっています。

TestPostService.svc.vb
Option Explicit On
Option Strict On

Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports System.ServiceModel.Activation
Imports System.ServiceModel.Web
Imports BaseLibrary.Library
Imports AspNetTest.ViewModels

<ServiceContract(Namespace:="")>
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)>
Public Class TestPostService

<OperationContract()>
<WebInvoke(Method:="POST",
BodyStyle:=WebMessageBodyStyle.Bare,
RequestFormat:=WebMessageFormat.Json,
ResponseFormat:=WebMessageFormat.Json,
UriTemplate:="TestPostFunction1"
)>
Public Function TestPostFunction1() As String

Dim json As String = OperationContext.Current.RequestContext.RequestMessage.ToString()
If String.IsNullOrEmpty(json) Then
Throw New InvalidOperationException("引数が設定されていません。")
End If

json = "<?xml version=""1.0"" encoding=""utf-8""?>" + System.Environment.NewLine + json
'Dim entity As Customer = JsonUtility.GetObject(Of Customer)(json)
Dim entity As Customer = XmlUtility.GetObject(Of Customer)(json)

'セッションを保存する
WcfService.Common.SetSession()

'クッキーを設定する
WcfService.Common.SetCookie()

Dim ret As Customer = entity
Return JsonUtility.GetJson(ret)

End Function

<OperationContract()>
<WebInvoke(Method:="POST",
BodyStyle:=WebMessageBodyStyle.Bare,
RequestFormat:=WebMessageFormat.Json,
ResponseFormat:=WebMessageFormat.Json,
UriTemplate:="TestPostFunction2"
)>
Public Function TestPostFunction2() As Message

Dim json As String = OperationContext.Current.RequestContext.RequestMessage.ToString()
If String.IsNullOrEmpty(json) Then
Throw New InvalidOperationException("引数が設定されていません。")
End If

json = "<?xml version=""1.0"" encoding=""utf-8""?>" + System.Environment.NewLine + json
'Dim entity As Customer = JsonUtility.GetObject(Of Customer)(json)
Dim entity As Customer = XmlUtility.GetObject(Of Customer)(json)

'セッションを保存する
WcfService.Common.SetSession()

'クッキーを設定する
WcfService.Common.SetCookie()

Dim ret As Customer = entity
Return WcfService.Common.GetJsonResponse(Of Customer)(ret)

End Function

End Class

※XmlUtility は以前の記事「XMLデータから配列を含むクラスに変換する方法 -デシリアライズ-」でもご紹介していますので、ご参考ください。



6.JavaScriptでGET/POSTの実行方法

以下のように Ajax で送受信し、jQuery で画面に表示しています。

WcfServiceTest.aspx
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="WcfServiceTest.aspx.vb" Inherits="AspNetTest.WcfServiceTest" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<style>
.inner {
margin: 30px;
}
.text {
margin: 10px;
height: 32px;
font-size: 28px;
width:100%;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/WcfService/TestService.svc" />
<asp:ServiceReference Path="~/WcfService/TestGetService.svc" />
</Services>
</asp:ScriptManager>
<div class="inner">
<p class="result text" ></p>
<p class="result_get1 text" ></p>
<p class="result_get2 text" ></p>
<p class="result_post1 text" ></p>
<p class="result_post2 text" ></p>
</div>
<script src="/App_Themes/default/scripts/jquery-1.10.2.min.js"></script>
<script>
$(function () {
GetTest0();

GetTest1();
GetTest2();
PostTest1();
PostTest2();
});

function GetTest0() {
var text = "テスト";
var test = new TestService().GetTestService(text, function (result) {
$('.result').text(result);
});
}

function GetTest1() {
var obj = { "Id": 1, "Name": "名前1", "Age": 10, "Note": "備考1" };
var json = JSON.stringify(obj);
var test = new TestGetService().TestGetFunction1(json, function (result) {
$('.result_get1').text(result);
});
}
function GetTest2() {
var obj = { "Id": 2, "Name": "名前2", "Age": 20, "Note": "備考2" };
var json = JSON.stringify(obj);
var test = new TestGetService().TestGetFunction2(json, function (result) {
$('.result_get2').text(JSON.stringify(result));
});
}
function PostTest1() {
var obj = { "Id": 3, "Name": "名前3", "Age": 30, "Note": "備考3" };
var json = JSON.stringify(obj);
$.ajax({
type: "post",
url: "http://localhost:53854/WcfService/TestPostService.svc/TestPostFunction1",
datatype: "json",
contentType: "application/json; charset=utf-8",
data: json,
success: function (data) {
$(".result_post1").text(data);
},
error: function (jqXHR, textStatus, errorThrown) {
$(".result_post1").text(jqXHR.responseText || textStatus);
}
});
}
function PostTest2() {
var obj = { "Id": 4, "Name": "名前4", "Age": 40, "Note": "備考4" };
var json = JSON.stringify(obj);
$.ajax({
type: "post",
url: "http://localhost:53854/WcfService/TestPostService.svc/TestPostFunction2",
datatype: "json",
contentType: "application/json; charset=utf-8",
data: json,
success: function (data) {
$(".result_post2").text(JSON.stringify(data));
},
error: function (jqXHR, textStatus, errorThrown) {
$(".result_post2").text(jqXHR.responseText || textStatus);
}
});
}
</script>
</form>
</body>
</html>



7.実行結果

GET / POST それぞれ JavaScript の実行結果は以下のようになります。
いずれも HTML に表示してしまえば実行結果が変わらないことが分かります。

aspnet_wcfservice_05.png



8.参考コード


Customer.vb
Option Explicit On
Option Strict On

Imports System.Runtime.Serialization

Namespace ViewModels

<DataContract(Name:="root", Namespace:="")>
<System.Xml.Serialization.XmlRoot("root")>
Public Class Customer

<DataMember(Name:="Id")>
<System.Xml.Serialization.XmlElement("Id", GetType(Integer))>
Public Property Id As Integer = 0

<DataMember(Name:="Name")>
<System.Xml.Serialization.XmlElement("Name", GetType(String))>
Public Property Name As String = String.Empty

<DataMember(Name:="Age")>
<System.Xml.Serialization.XmlElement("Age", GetType(Integer))>
Public Property Age As Integer = 0

<DataMember(Name:="Gender")>
<System.Xml.Serialization.XmlElement("Gender", GetType(Integer))>
Public Property Gender As Integer = 0

<DataMember(Name:="Note")>
<System.Xml.Serialization.XmlElement("Note", GetType(String))>
Public Property Note As String = String.Empty

End Class

End Namespace

WcfService.Common.vb
Option Explicit On
Option Strict On


Imports System.Net
Imports System.ServiceModel.Activation
Imports System.ServiceModel.Web
Imports System.IO
Imports System.ServiceModel.Channels
Imports System.Web.Script.Serialization

Namespace WcfService

Public Class Common

''' <summary>
''' セッションを保存する
''' </summary>
Public Shared Sub SetSession()

HttpContext.Current.Session("ASPNET_Session_Test") = "ASPNET_Session_Value"

End Sub

''' <summary>
''' クッキーを設定する
''' </summary>
Public Shared Sub SetCookie()

'クッキーの設定
Dim cookie As New HttpCookie("ASPNET_Cookie_Test")
cookie.HttpOnly = True
cookie.Expires = DateTime.Now.AddMonths(1)
cookie.Value = "ASPNET_Cookie_Value"
HttpContext.Current.Response.SetCookie(cookie)

End Sub

''' <summary>
''' System.ServiceModel.Channels.Messageを取得する
''' </summary>
''' <param name="instance">JSONに変換するインスタンス</param>
''' <returns>json</returns>
Public Shared Function GetJsonResponse(Of T)(ByVal instance As T) As Message

Dim context As WebOperationContext = WebOperationContext.Current
context.OutgoingResponse.Headers.Add("X-Content-Type-Options", "nosniff")

context.OutgoingResponse.Format = WebMessageFormat.Json

'Content-Type の書き換え
context.OutgoingResponse.ContentType = "application/json; charset=utf-8"

Return context.CreateJsonResponse(instance)

End Function

''' <summary>
''' System.ServiceModel.Channels.Messageを取得する
''' </summary>
''' <param name="text">JSON文字列</param>
''' <returns>String</returns>
''' <remarks>エスケープされていないJSON文字列を返すことができる</remarks>
Private Function GetTextResponse(ByVal text As String) As System.ServiceModel.Channels.Message

'Add 'X-Content-Type-Options: nosniff' header'
WebOperationContext.Current.OutgoingResponse.Headers.Add("X-Content-Type-Options", "nosniff")
WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json
Return WebOperationContext.Current.CreateTextResponse(text, "application/json; charset=utf-8", Encoding.UTF8)

End Function

Public Shared Function GetObjectFromJson(Of T)(ByVal json As String) As T

Dim seriaizer As JavaScriptSerializer = New JavaScriptSerializer()
Dim obj As T = DirectCast(seriaizer.Deserialize(json, GetType(T)), T)

End Function

Public Shared Function GetPostData() As String

Dim r As New StreamReader(HttpContext.Current.Request.InputStream)
Dim json As String = r.ReadToEnd()

Return json

End Function

End Class

End Namespace


以上で WCF サービスで GET または POST で JSON を送受信する機能が実装できました。POST は JavaScript で、GET は JavaScript でも URL 指定でも実行できますので、不必要なポストバック無しに VB や DB 等の値を取得することができますので、レスポンス的に優れていますね。






最後までお読みいただきありがとうございます。
いかがでしたでしょうか。他にも asp.net に関連する記事を投稿しておりますのでよろしければご参考くださいませ。



関連記事

コメント

コメントの投稿

※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。

 入力されていないコメントには返信しませんのであらかじめご了承くださいませ。

※ニックネームでも良いので必ずご入力ください。

    

※必ずご入力ください。

    
    

※必ずご入力ください。

※技術的な質問には環境やエラーについて正確かつ詳細にお教えください。

・正確なエラーの内容

・Windowsのバージョン番号

・Visual Studioのバージョン

・機器の型番

・アプリやソフトのバージョン

    

カテゴリ別記事一覧

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Catalina 10.15 / Mojave 10.14 / High Sierra 10.13 / Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
【データベース】
Oracle 10g/9i
SQLServer 2016/2008R2/2005/2000
SQLAnywhere 16/11/8
【BI/レポートツール】
Cognos ReportNet (IBM)
Microsoft PowerBI
ActiveReport (GrapeCity)
CrystalReport
【OCX関連】
GrapeCity InputMan SPREAD MultiRow GridView
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS jQuery IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。