QA@IT

ASP.NETで、AjaxからWCFサービスを呼び出そうとしたが、パラメータが渡されません。

4242 PV

お世話になります。
Microsoft Visual Studio 2013 Community Edhition のWebFormsで開発しております。
下記のように、jQueryでAjaxを用いてWCFサービスを呼び出しました。
すると、LogInMeボタンを押したとき、Function fnVerifyID(ByVal ID As String, ByVal PASS As String) のIDとPASSがNothingになってしまい、値を渡すことができません。
1) data:paraではなく、コメントにしてある data: { ID: "テストID", PASS: "テストPASS" } に変更すると、パラメータが期待通りに渡されます。
2) txtUserNameにusername,txtPasswordにpassと入力してからLogInMeボタンを押すと、Firefoxのデバッガ上では、添付図のように一見JSONの文字列となっていますが、渡されません。

どのように修正したら良いでしょうか。
rapture_20151003005419.jpg
【Test.aspx】

<%@ Page Title="" Language="vb" AutoEventWireup="false" MasterPageFile="~/Site.Mobile.Master" CodeBehind="Test.aspx.vb" Inherits="Shop.Daishin" %>
<%--<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="FeaturedContent" runat="server">
</asp:Content>--%>
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">

<head>
    <!DOCTYPE html> 
<title>テストタイトル</title>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css"/>
<link rel="stylesheet" href="css/custom.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
    <%--<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>--%>
<script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
<script src="js/jCarousel.min.js" type="application/x-javascript" charset="utf-8"></script>
<script src="js/custom.js"></script>


    <script type="text/javascript">

    $(function () {

        $('#LogInMe').click(function () {

            var Para = '{ID: ' +  '"'+ $('#txtUserName').val() +'"'+ ', PASS: ' + '"'+ $('#txtPassword').val() + '"}'

            $.ajax({
                url: '/TestWCF.svc/fnVerifyID', // ポスト先のURL
                //デフォルトは type: 'GET',
                dataType: 'json', // HTTPメソッドの種類
                contentType: "application/json; charset=utf-8",

                //data: { ID: "テストID", PASS: "テストPASS" },    // これは渡されます
                data: Para,

                success: function (response) {
                        var obj = JSON.parse(response.d);            
                        alert(obj.Name)
                }, 

                error: function (xhr, status, err) {
                    alert('Exeption:');

                } 
            });

        });
    });

</script>

</head>
<body>

  <div data-role="page" data-add-back-btn="true" id="p-listview-thumbnail" >

        <div data-role="header" data-position="fixed" data-theme="d">
           <h1></h1>
            <a href="#Family" data-icon="gear" class="ui-btn-right" data-iconpos="notext" data-theme="d" >Options</a>   
            <input type="text" id="txtUserName" placeholder="Username" />
            <input type="password" name="passwordinput" id="txtPassword"  placeholder="Password" value=""  />
            <a href="javascript:Authenticate();" id="LogInMe" data-role="button" data-icon="check" data-iconpos="right">Log Me In!</a>
             <label for="basic_name" id="lblMessage"></label>            
        </div><!-- /content -->

</body>
</html>

</asp:Content>

【TestWCF.svc.vb】

Imports System.ServiceModel
Imports System.ServiceModel.Activation
Imports System.ServiceModel.Web
Imports System.Web.Providers.Entities
Imports System.Runtime.Serialization.Json
Imports System.ServiceModel.Description
Imports System.Runtime.Serialization
Imports Newtonsoft.Json

<ServiceContract()>
Public Interface IService1

    <OperationContract()> _
        <WebInvoke(Method:="POST", ResponseFormat:=WebMessageFormat.Json)> _
    Function fnVerifyID(ByVal ID As String, ByVal PASS As String)

End Interface
<DataContract()> _
Public Class csVerifyID
    Dim sID As String
    Dim iFlg As Integer
    Dim sName As String


    <DataMember()> _
    Public Property Name() As String
        Get
            Return sName
        End Get
        Set(value As String)
            sName = value
        End Set
    End Property

End Class

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


    <WebGet()>
    Public Function fnVerifyID(ByVal ID As String, ByVal PASS As String)

        Dim Hyouji As String = CStr(ID) & CStr(PASS)

        Dim objVeryfyID As New csVerifyID

        objVeryfyID.Name = "なまえ"

        Dim person As String = JsonConvert.SerializeObject(objVeryfyID)

        Return person

    End Function
    <OperationContract()>
    Public Sub DoWork()
        ' Add your operation implementation here
    End Sub

End Class

回答

jsの部分しか見てないですが

これだと上手くいって

$.ajax({
  // 中略
  data: { ID: "テストID", PASS: "テストPASS" },    // これは渡されます
  // 中略
});

こちらだと上手くいかない

var Para = '{ID: ' +  '"'+ $('#txtUserName').val() +'"'+ ', PASS: ' + '"'+ $('#txtPassword').val() + '"}'
$.ajax({
  // 中略
  data: Para
  // 中略
});

という話ですよね?

前者はjavascriptのオブジェクトを指定しているのに後者は文字列を指定しています。

こうなると思うんですがどうでしょう。

var Para = {ID: $('#txtUserName').val(), PASS: $('#txtPassword').val() };
$.ajax({
  // 中略
  data: Para
  // 中略
});

これは以下と同じです。

var Para = {};
Para.ID = $('#txtUserName').val();
Para.PASS = $('#txtPassword').val();

$.ajax({
  // 中略
  data: Para
  // 中略
});

ここまででわかったなら以降は読むのは不要ですが、もう少し詳しく書けば

$('#txtUserName').val()"user"$('#txtPassword').val()"pass" だったとき

var Para = '{ID: ' +  '"'+ $('#txtUserName').val() +'"'+ ', PASS: ' + '"'+ $('#txtPassword').val() + '"}';

とは

var Para = '{ID: ' +  '"'+ "user" +'"'+ ', PASS: ' + '"'+ "pass" + '"}';
console.log(typeof Para); // コンソールに型名を出力 -> string 

です。

しかし上手くいく書き方(data: { ID: "テストID", PASS: "テストPASS" })のコロンより右に従えば

var Para = { ID: "user", PASS: "pass" };
console.log(typeof Para); // コンソールに型名を出力 -> object 

のようになるはずです。

ここから "user", "pass" を変数にした場合は

var userId = "user";
var password = "pass";
var Para = { ID: userId, PASS: password };

今回は$('#txtUserName').val()を使いたいわけですから、

var userId = $('#txtUserName').val();
var password = $('#txtPassword').val();
var Para = { ID: userId, PASS: password };

仕上げに、変数からではなく関数の戻り値直接使う形にして完成です。

var Para = { ID: $('#txtUserName').val(), PASS: $('#txtPassword').val() };

あと、javascriptでは変数名は小文字始まりがいいですよ。

編集 履歴 (0)
  • ご丁寧にありがとうございます。できました。
    -

以前、質問者さんの立てた別スレッド(URL 下記)で、私が jQuery.Ajax の data のサンプルを示したようにしてはいかがですか?

http://qa.atmarkit.co.jp/q/9468

【2015/10/4 12:37 追伸】

いまさらながらですが、POST 要求ではなく GET 要求というところを見落としていたことに気がつきました。すみません。

data オプションに設定するのは、GET 要求の場合は JavaScript オブジェクトにする必要があるので、上の URL のサンプル(POST 要求)のように JSON 文字列を設定したのではダメでした。(オブジェクトの場合は application/x-www-form-urlencoded クエリ文字列形式に変換されますが、string の場合はそのままになります。JSON 文字列を URL に追加して GET 要求してもダメというのが理由です)

POST 要求する場合は、逆に、data オプションには JSON 文字列を設定する必要があります。(POST 要求で application/x-www-form-urlencoded クエリ文字列形式に変換されたデータをコンテンツとして送信してもダメということです)

GET と POST の使い分けですが、以下のことを考えると、今回のケースでは POST の方がよさそうです。

jQuery - AJAX get() and post() Methods
http://www.w3schools.com/jquery/jquery_ajax_get_post.asp

GET - Requests data from a specified resource
POST - Submits data to be processed to a specified resource

編集 履歴 (1)
  • ありがとうございます。
    data: '{"ID":"' + $('#txtUserName').val() +'"'+ ', "PASS":' + '"'+ $('#txtPassword').val() + '"}'
    …と、してみたのですが状態は変わらないようです。
    -
  • 最初に聞くべきでしたが、そもそも送り側の問題か受け側の問題かの切り分けはできているのでしょうか? 最初の質問の 1) では期待通りになるようなことが書いてあったので、送り側の問題だと思っていたのですが。 -
  • 送り側の問題(送信する JSON 文字列に問題がある?)ということなら、期待通りになる時とならない時で、Fiddler2 などのパケットキャプチャツールを使って、実際にブラウザからサーバーに送信される JSON 文字列がどう違うか較べてはいかがですか? -
  • もし、送り側の問題か受け側の問題かの切り分けができていないということであれば、そこまでは質問者さんの方でやっていただけませんか? -
  • いまさらながらですが、POST 要求ではなく GET 要求というところを見落としていたことに気がつきました。すみません。問題は送信側にあることに間違いないようですね。 -
  • 折角教えていただいのですが、設定がうまくないせいかFiddler2での確認は現時点ではできませんでした。今後このようなツールを活用できるように努力したいと思います。 -
  • GETとPOSTの場合で異なるのですね。参考URLもありがとうございます。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。