[CLOSED] REST with WCF - part 2

  1. #1

    [CLOSED] REST with WCF - part 2

    My REST-based WCF application using Ext.NET 1.0 works fine for retrieving data, but now I'm add functionality to update data, so here's the page markup:
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="CrudRest.aspx.cs" Inherits="TWA.Forms.CrudRest" %>
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <ext:Store runat="server" id="StoreRestful" AutoLoad="true" Restful="true">
          <BaseParams>
            <ext:Parameter Name="start" Value="={0}" />
          </BaseParams>
          <Proxy>
            <ext:HttpProxy Json="true" Url="~/Service/Candidate.svc">
            </ext:HttpProxy>
          </Proxy>
          <Reader>
            <ext:JsonReader IDProperty="PersonId" Root="Data" TotalProperty="Count" SuccessProperty="Success">
              <Fields>
                <ext:RecordField Name="PersonId" Type="Int"/>
                <ext:RecordField Name="FirstName" />
                <ext:RecordField Name="Surname" />
                <ext:RecordField Name="Initials" />
                <ext:RecordField Name="JobTitle" />
                <ext:RecordField Name="DateOfBirth" Type="Date" DateFormat="M$" />
              </Fields>
            </ext:JsonReader>
          </Reader>
          <Listeners>
            <BeforeLoad Handler="debugger;this.proxy.setApi('read','http://lonmw65502.fm.rbsgrp.net/TWA/Service/candidate.svc/' + options.params.start);" />
            <BeforeSave Handler="debugger;this.proxy.setApi('update','http://lonmw65502.fm.rbsgrp.net/TWA/Service/candidate.svc/' + options.params.start);" />
            <DataChanged Handler="debugger;var rec=this.getAt(0)||{};#{FormPanel2}.getForm().loadRecord(rec);#{FormPanel2}.clearInvalid();" />
          </Listeners>
        </ext:Store>
        <ext:ResourceManager ID="ResourceManager1" runat="server">
        </ext:ResourceManager>
        <ext:Viewport ID="Viewport1" runat="server" Layout="form" StyleSpec="margin:10px">
            <Items>
                <ext:FormPanel ID="FormPanel2" runat="server" ButtonAlign="Right" Height="230" Padding="5"
                    Title="Candidates (RESTful)" Width="500" LabelSeparator="">
                    <Items>
                        <ext:TextField ID="RestFirstName" DataIndex="FirstName" runat="server" AnchorHorizontal="100%" FieldLabel="Name">
                        </ext:TextField>
                        <ext:TextField ID="RestInitials" DataIndex="Initials" runat="server" AnchorHorizontal="100%" FieldLabel="Initials">
                        </ext:TextField>
                        <ext:TextField ID="RestSurname" DataIndex="Surname" runat="server" AnchorHorizontal="100%" FieldLabel="Surname">
                        </ext:TextField>
                        <ext:TextField ID="RestJobTitle" DataIndex="JobTitle" runat="server" AnchorHorizontal="100%" FieldLabel="Job title">
                        </ext:TextField>
                        <ext:DateField ID="RestDOB" DataIndex="DateOfBirth" runat="server" AnchorHorizontal="100%" FieldLabel="Date of birth" >
                        </ext:DateField>
                    </Items>
                    <Buttons>
                        <ext:Button ID="Button2" runat="server" Icon="Disk" Text="Submit">
                          <Listeners>
                            <Click Handler="
                              debugger;var start=#{StoreRestful}.getAt(0).id,rec=#{FormPanel2}.form.getFieldValues();#{StoreRestful}.loadData(rec);#{StoreRestful}.save();
                            " />
                          </Listeners>
                        </ext:Button>
                    </Buttons>
                    <BottomBar>
                        <ext:PagingToolbar ID="PagingToolbar2" runat="server" StoreID="StoreRestful" PageSize="1" DisplayInfo="True" LastText="Last record" NextText="Next record" PrevText="Previous record" FirstText="First record" DisplayMsg="Displaying {0} of {2}" BeforePageText="Record">
                        <Listeners>
                        </Listeners>
                        </ext:PagingToolbar>
                    </BottomBar>
                </ext:FormPanel>
            </Items>
        </ext:Viewport>
        </form>
    </body>
    </html>
    There is no custom code-behind but the service implementation is:
        [ServiceContract]
        public interface ICandidate
        {
            [OperationContract]
            [WebGet(UriTemplate="/{index}",
                    RequestFormat=WebMessageFormat.Json,
                    ResponseFormat=WebMessageFormat.Json)]
            Common.RestResponse<Person> GetPersonByIndex(string index);
    
            /*[OperationContract]
            [WebInvoke(Method="PUT", RequestFormat=WebMessageFormat.Json, UriTemplate="/{index}")]
            void UpdatePerson(Person person);*/
        }
    
        [AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)]
        public class Candidate : ICandidate
        {
            public Common.RestResponse<Person> GetPersonByIndex(string index)
            {
                Common.RestResponse<Person> result = new TWA.Common.RestResponse<Person>();
    
                int Index = 0;
                if (Int32.TryParse(index, out Index)) 
                {
                    List<Person> list = PersonService.GetPersonList(true, true, true);
                    if (list.Count > Index)
                    {
                        result.Success = true;
                        result.Count = list.Count;
                        result.Data = list[Index];
                    }
                }
                return result;
            }
    
            public void UpdatePerson(Person person)
            {
                RBS.RegRisk.ApprovedPersons.WebUI._Common.Classes.Util.UpdateAuditInfo(person);
                PersonService.SavePerson(person);
            }
        }
    That defines the service contract interface and the implementation.

    The page works fine for retrieving data but if I uncomment the UpdatePerson method in the interface, I get an error when the data is loaded saying that
    Operation 'UpdatePerson' in contract 'ICandidate' has a UriTemplate that expects a parameter named 'INDEX',
    but there is no input parameter with that name on the operation.
    Why is this happening? I haven't called the REST update/PUT associated method so I'm wondering why that error occurs when calling the service to get the data.
    Last edited by Daniil; Apr 25, 2011 at 7:54 AM. Reason: [CLOSED]
  2. #2
    Hi,

    Do you see PUT request in the Fiddller? If no then the problem is not related with Ext.Net
    If PUT request is initiated from client side then please post test application which we can test locally
  3. #3
    It does look like a WCF issue so I'll investigate further and post back by findings...
  4. #4
    I took a closer read of this article on building REST services with WCF and it dawned on me that I was missing a crucial method argument in the UpdatePerson method. The person method signature now becomes
    void UpdatePerson(string index, Person person)
    Because the Person class contains an id as a property which I was going to use to update it, the index argument isn't really necessary so I can do without it and solve my problem that way too.
  5. #5
    I'm struggling to update data using REST methods. Here's my page markup:
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="CrudRest.aspx.cs" Inherits="TWA.Forms.CrudRest" %>
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <ext:Store runat="server" id="StoreRestful" AutoLoad="true" Restful="true">
          <BaseParams>
            <ext:Parameter Name="start" Value="={0}" />
          </BaseParams>
          <Proxy>
            <ext:HttpProxy Json="true" Url="~/Service/Candidate.svc">
            </ext:HttpProxy>
          </Proxy>
          <Reader>
            <ext:JsonReader IDProperty="PersonId" Root="Data" TotalProperty="Count" SuccessProperty="Success">
              <Fields>
                <ext:RecordField Name="PersonId" Type="Int"/>
                <ext:RecordField Name="FirstName" />
                <ext:RecordField Name="Surname" />
                <ext:RecordField Name="Initials" />
                <ext:RecordField Name="JobTitle" />
                <ext:RecordField Name="DateOfBirth" Type="Date" DateFormat="M$" />
              </Fields>
            </ext:JsonReader>
          </Reader>
          <Listeners>
            <BeforeLoad Handler="debugger;
            this.proxy.setApi('read','http://lonmw65502.fm.rbsgrp.net/TWA/Service/candidate.svc/' + options.params.start);" />
            <BeforeSave Handler="debugger;
            this.proxy.setApi('update','http://lonmw65502.fm.rbsgrp.net/TWA/Service/candidate.svc');" />
            <DataChanged Handler="
            var rec=this.getAt(0)||{};
            #{FormPanel2}.getForm().loadRecord(rec);
            #{FormPanel2}.clearInvalid();" />
          </Listeners>
        </ext:Store>
        <ext:ResourceManager ID="ResourceManager1" runat="server">
        </ext:ResourceManager>
        <ext:Viewport ID="Viewport1" runat="server" Layout="form" StyleSpec="margin:10px">
            <Items>
                <ext:FormPanel ID="FormPanel2" runat="server" ButtonAlign="Right" Height="230" Padding="5"
                    Title="Candidates (RESTful)" Width="500" LabelSeparator="">
                    <Items>
                        <ext:TextField ID="RestFirstName" DataIndex="FirstName" runat="server" AnchorHorizontal="100%" FieldLabel="Name">
                        </ext:TextField>
                        <ext:TextField ID="RestInitials" DataIndex="Initials" runat="server" AnchorHorizontal="100%" FieldLabel="Initials">
                        </ext:TextField>
                        <ext:TextField ID="RestSurname" DataIndex="Surname" runat="server" AnchorHorizontal="100%" FieldLabel="Surname">
                        </ext:TextField>
                        <ext:TextField ID="RestJobTitle" DataIndex="JobTitle" runat="server" AnchorHorizontal="100%" FieldLabel="Job title">
                        </ext:TextField>
                        <ext:DateField ID="RestDOB" DataIndex="DateOfBirth" runat="server" AnchorHorizontal="100%" FieldLabel="Date of birth" >
                        </ext:DateField>
                    </Items>
                    <Buttons>
                        <ext:Button ID="Button2" runat="server" Icon="Disk" Text="Submit">
                          <Listeners>
                            <Click Handler="
                              debugger;
                              var rec=#{StoreRestful}.getAt(0),
                                  start=rec.id;
                                  #{FormPanel2}.getForm().updateRecord(rec);
                                  #{StoreRestful}.save();
                            " />
                          </Listeners>
                        </ext:Button>
                    </Buttons>
                    <BottomBar>
                        <ext:PagingToolbar ID="PagingToolbar2" runat="server" StoreID="StoreRestful" PageSize="1" DisplayInfo="True" LastText="Last record" NextText="Next record" PrevText="Previous record" FirstText="First record" DisplayMsg="Displaying {0} of {2}" BeforePageText="Record">
                        <Listeners>
                        </Listeners>
                        </ext:PagingToolbar>
                    </BottomBar>
                </ext:FormPanel>
            </Items>
        </ext:Viewport>
        </form>
    </body>
    </html>
    There's no custom code-behind. In the BeforeSave handler I'm setting the correct service URL for the proxy "update" action which corresponds to a PUT REST action.
    Here's the service contract:
        [ServiceContract]
        public interface ICandidate
        {
            [OperationContract]
            Common.RestResponse<Person> GetPersonByIndex(string index);
    
            [OperationContract]
            void UpdatePerson(string id, Person person);
        }
    and implementation:
        [AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Required)]
        public class Candidate : ICandidate
        {
            [WebGet(UriTemplate = "/{index}",
                    RequestFormat = WebMessageFormat.Json,
                    ResponseFormat = WebMessageFormat.Json)]
            public Common.RestResponse<Person> GetPersonByIndex(string index)
            {
                Common.RestResponse<Person> result = new TWA.Common.RestResponse<Person>();
    
                int Index = 0;
                if (Int32.TryParse(index, out Index)) 
                {
                    List<Person> list = PersonService.GetPersonList(true, true, true);
                    if (list.Count > Index)
                    {
                        result.Success = true;
                        result.Count = list.Count;
                        result.Data = list[Index];
                    }
                }
                return result;
            }
    
            [WebInvoke(Method = "PUT", RequestFormat = WebMessageFormat.Json, UriTemplate = "/{id}")]
            public void UpdatePerson(string id, Person person)
            {
                if (person.JobTitle != null)
                    PersonService.SavePerson(person);
            }
        }
    Editing the form data and submitting the changes results in the following request:
    PUT http://localhost/TWA/Service/candidate.svc/2244?Data=%7B%22PersonId%22%3A2244%2C%22FirstName%22%3A%22Annette%22%2C%22Surname%22%3A%22Austin%22%2C%22Initials%22%3A%22Zara%22%2C%22JobTitle%22%3A%22CAO%2C%20Equities%22%2C%22DateOfBirth%22%3A%221957-01-03T00%3A00%3A00%22%7D HTTP/1.1
    Accept: */*
    Referer: http://localhost/twa/forms/crudrest.aspx
    x-requested-with: XMLHttpRequest
    Content-Type: application/json
    Accept-Encoding: gzip, deflate
    Content-Length: 172
    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
    Host: localhost
    Connection: Keep-Alive
    Pragma: no-cache
    Authorization: Negotiate TlRMTVNTUAADAAAAAAAAAEgAAAAAAAAASAAAAAAAAABIAAAAAAAAAEgAAAAAAAAASAAAAAAAAABIAAAABcKIogUBKAoAAAAP
    Accept-Language: en-gb
    
    {"Data":"{\"PersonId\":2244,\"FirstName\":\"Annette\",\"Surname\":\"Austin\",\"Initials\":\"Zara\",\"JobTitle\":\"CAO, Equities\",\"DateOfBirth\":\"1957-01-03T00:00:00\"}"}
    which results in the following response:
    HTTP/1.1 409 Conflict
    Server: Microsoft-IIS/5.1
    Date: Thu, 14 Apr 2011 09:23:46 GMT
    X-Powered-By: ASP.NET
    Connection: close
    Content-Type: text/html
    Content-Length: 43
    
    <body><h2>HTTP/1.1 409 Conflict</h2></body>
    I've set a breakpoint in the service method but it's never hit so I'm guessing the IIS server is returning the 409 status before the service sees the request?
    Also, I notice that the PUT url has the data appended as a query string. Why?

    Does everything look okay with my code? As far as I can tell it's all okay but would welcome any feedback or suggestions on how to get this fairly simple RESTful form working.
  6. #6
    Hi,

    We are not WCF experts. Do you know which request is expected by your WCF service? Do you able to create correct XmlHttpRequest to WCF service (in this case we will be able to understand which request must be built by Ext.Net store)?
  7. #7
    The call to
    #{StoreRestful}.save()
    in Button2's click handler triggers the store's BeforeSave handler (line 35) where I specify the service URL. As can be seen from the request header, a PUT request is initiated from Ext.NET store but the request URL also contains the tacked-on query-string of encoded JSON and I suspect that may be causing the issue.

    Why is the encoded JSON tacked-on to the end of the PUT request as well as being included in the request body?
  8. #8
    Hi,

    I don't know (without a sample to reproduce)
    I cannot reproduce it on online sample
    https://examples1.ext.net/#/GridPanel/Restful/Overview/

    Try to update from SVN and retest

    Here is my test case (based on your sample)
    I added button "Add" to create temp record, click on that button, fill fields and click Submit
    Notes:
    - i changed Submit listener because it is need to call 'updateRecord'
    - restfull store automatically add id to the url for update request therefore BeforeSave is removed

    Fiddler shows for me that query string has no data

    <%@ Page Language="C#" %>
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
     
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <ext:Store runat="server" id="StoreRestful" AutoLoad="true" Restful="true">
          <BaseParams>
            <ext:Parameter Name="start" Value="={0}" />
          </BaseParams>
          <Proxy>
            <ext:HttpProxy Json="true" Url="~/Service/Candidate.svc">            
            </ext:HttpProxy>
          </Proxy>
          <Reader>
            <ext:JsonReader IDProperty="PersonId" Root="Data" TotalProperty="Count" SuccessProperty="Success">
              <Fields>
                <ext:RecordField Name="PersonId" Type="Int"/>
                <ext:RecordField Name="FirstName" />
                <ext:RecordField Name="Surname" />
                <ext:RecordField Name="Initials" />
                <ext:RecordField Name="JobTitle" />
                <ext:RecordField Name="DateOfBirth" Type="Date" DateFormat="M$" />
              </Fields>
            </ext:JsonReader>
          </Reader>      
          <Listeners>
            <BeforeLoad Handler="this.proxy.setApi('read','candidate.svc/' + options.params.start);" />        
            <DataChanged Handler="var rec=this.getAt(0)||{};#{FormPanel2}.getForm().loadRecord(rec);#{FormPanel2}.clearInvalid();" />
          </Listeners>
        </ext:Store>
        <ext:ResourceManager ID="ResourceManager1" runat="server" ScriptMode="Debug">
        </ext:ResourceManager>
        <ext:Viewport ID="Viewport1" runat="server" Layout="form" StyleSpec="margin:10px">
            <Items>
                <ext:FormPanel ID="FormPanel2" runat="server" ButtonAlign="Right" Height="230" Padding="5"
                    Title="Candidates (RESTful)" Width="500" LabelSeparator="">
                    <Items>
                        <ext:TextField ID="RestFirstName" DataIndex="FirstName" runat="server" AnchorHorizontal="100%" FieldLabel="Name">
                        </ext:TextField>
                        <ext:TextField ID="RestInitials" DataIndex="Initials" runat="server" AnchorHorizontal="100%" FieldLabel="Initials">
                        </ext:TextField>
                        <ext:TextField ID="RestSurname" DataIndex="Surname" runat="server" AnchorHorizontal="100%" FieldLabel="Surname">
                        </ext:TextField>
                        <ext:TextField ID="RestJobTitle" DataIndex="JobTitle" runat="server" AnchorHorizontal="100%" FieldLabel="Job title">
                        </ext:TextField>
                        <ext:DateField ID="RestDOB" DataIndex="DateOfBirth" runat="server" AnchorHorizontal="100%" FieldLabel="Date of birth" >
                        </ext:DateField>
                    </Items>
                    <Buttons>
                        <ext:Button ID="Button2" runat="server" Icon="Disk" Text="Submit">
                          <Listeners>
                            <Click Handler="#{FormPanel2}.getForm().updateRecord(#{StoreRestful}.getAt(0));#{StoreRestful}.save();" />
                          </Listeners>
                        </ext:Button>
                        
                        <ext:Button ID="Button22" runat="server" Icon="Disk" Text="Add">
                          <Listeners>
                            <Click Handler="#{StoreRestful}.addRecord({PersonId : 0});" />
                          </Listeners>
                        </ext:Button>
                    </Buttons>
                    <BottomBar>
                        <ext:PagingToolbar ID="PagingToolbar2" runat="server" StoreID="StoreRestful" PageSize="1" DisplayInfo="True" LastText="Last record" NextText="Next record" PrevText="Previous record" FirstText="First record" DisplayMsg="Displaying {0} of {2}" BeforePageText="Record">
                        <Listeners>
                        </Listeners>
                        </ext:PagingToolbar>
                    </BottomBar>
                </ext:FormPanel>
            </Items>
        </ext:Viewport>
        </form>
    </body>
    </html>

Similar Threads

  1. [CLOSED] Rest api.
    By farisqadadeh in forum 1.x Legacy Premium Help
    Replies: 15
    Last Post: Aug 19, 2011, 11:22 AM
  2. [CLOSED] REST with WCF and Ext.NET 1.0
    By daneel in forum 1.x Legacy Premium Help
    Replies: 2
    Last Post: Apr 11, 2011, 10:34 AM
  3. [CLOSED] EventStore and REST API
    By craig2005 in forum 1.x Legacy Premium Help
    Replies: 4
    Last Post: Mar 04, 2011, 3:19 PM
  4. [CLOSED] [1.0] Store and REST
    By Timothy in forum 1.x Legacy Premium Help
    Replies: 8
    Last Post: Feb 28, 2010, 4:19 AM
  5. [CLOSED] [1.0] REST question
    By tdracz in forum 1.x Legacy Premium Help
    Replies: 12
    Last Post: Nov 30, 2009, 12:48 PM

Tags for this Thread

Posting Permissions