Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Binding to .NET WSDL Web Service

    Hi

    Below is a fragment of a WSDL document. The fragment below is based on "Ability" data. The web service wraps the data as an "ArrayOfAbilityData". This contains "AbilityData". In turn, this has two fields "CurrentAbility" and "OriginalAbility" of type "Ability".

    The concept of "Current" and "Original" comes from the ADO.Net DataSet which has in-built change tracking. It retains a copy of the data in an "Original" bucket, and changes to the data are made to the row in the "Current" bucket. The difference in the Original and Current values can be detected and gives targeted Optimistic Concurrency support.

    The web service based on this DataSet approach gives the Original and Current values so that when/where required (generally a remote .NET client piece), a DataSet could be rebuilt on the client side. Using SmartClient, the DataSet obviously cannot be rebuilt but, the Original and Current data is automatically sent anyway. There is nothing I can do about the data sent by the web service. This configuration is how I will receive all web-service data in this particular application.

    Here is the real question. I have been reading the Client-side Data Integration topic and am starting to understand this. However, I wonder if you can cast some light on how I can "tell" SmartClient that I want to bind to and operate on the "CurrentData" only, and then return the "CurrentData" with any changes and the "Original" data (that clearly has had no changes made to it) so that the web service can rebuild the ADO.Net DataSet (server-side) and consequently "know" about changes that have occured browser-side by comparing "Current" and "Original" data.

    In otherwords, how do I express this in code in SmartClient?

    Thanks

    -=H

    Code:
    - <s:complexType name="ArrayOfAbilityData">
    - <s:sequence>
      <s:element minOccurs="0" maxOccurs="unbounded" name="AbilityData" nillable="true" type="tns:AbilityData" /> 
      </s:sequence>
      </s:complexType>
    - <s:complexType name="AbilityData">
    - <s:sequence>
      <s:element minOccurs="0" maxOccurs="1" name="OriginalAbility" type="tns:Ability" /> 
      <s:element minOccurs="0" maxOccurs="1" name="CurrentAbility" type="tns:Ability" /> 
      </s:sequence>
      </s:complexType>
    - <s:complexType name="Ability">
    - <s:sequence>
      <s:element minOccurs="1" maxOccurs="1" name="AbilityId" type="s:int" /> 
      <s:element minOccurs="0" maxOccurs="1" name="AbilityName" type="s:string" /> 
      </s:sequence>
      </s:complexType>

    #2
    Hi Henry,

    Could you clarify - will you ever load a dataset where Original and Current differs when SmartClient first receives the data?

    We'll assume not, which is simpler. In that case you just want to define a recordXPath on your DataSource that selects the CurrentAbility records only only. Ignoring namingspaces it would be "//CurrentAbility/Ability", but you have to have your namespace prefixes right and the snippet of XML Schema you showed doesn't include them - see the docs for DataSource.xmlNamespaces.

    Then take a look at dsRequest.oldValues - SmartClient will always send the original values as SmartClient first received them whenever submitting a save (so basically, built-in optimistic concurrency support). You have an opportunity in DataSource.transformRequest to make the oldValues part of dsRequest.data such that they will be encoded into your SOAP request (eg, potentially as the "OriginalData" element if that's what your service expects).

    However, further wrinkle - I'm guessing this is a "mass update" scenario ala listGrid.autoSaveEdits:false. In this case when using the SmartClient Server you get several logically separate DSRequests in a "queue" that takes one HTTP turnaround. To do the equivalent with a web service you need to interrogate the grid using getAllEditRows() and getEditValues() to find the edits that have been to the record, then you'll need to use WebService.callOperation() to submit all the gathered data. Note that the reason you'd use callOperation() as opposed to the DataSource is that you are not performing one of the normal CRUD operations but instead a batch of CRUD operations.

    Make sense?

    Comment


      #3
      Hi,

      Thanks for your earlier reply.

      >Could you clarify - will you ever load a dataset where Original and Current differs when SmartClient first receives the data?

      No, the code will always start out the same (as you guessed).

      I have put some code below that doesn't work but if you could just sanity check it, it would be appreciated. I am getting
      the following error:-

      Access to restricted URI denied" code: "1012
      file:///C:/SmartClient_651_Evaluation/smartclientSDK/isomorphic/system/modules/ISC_Core.js
      Line 1026

      I have tried to run the DeveloperConsole but when I load the HTML file containing my sample code, the DevConsole just will not fire and I am not sure why? However, as the above code immediately errors, maybe this is having an effect?

      For now, here is a little background around my configuration. I am running the ISC/my code in FireFox and I have the ISC embedded server running too. My web services, as you can see, are being called against "localhost" via IIS7 on the same machine. I don't know whether this is a potential source of conflict?

      Many thanks,

      -H


      Code:
      	isc.ListGrid.create({
      		    ID: "jobGrid",
      		    width:"100%", alternateRecordStyles:true, showAllRecords:true
      		});
      		
      		isc.DataSource.create({
      		    ID:"jobList",
      		    xmlNamespaces : {zitoc:"http://tempuri.org/"},  
      		    recordXPath:"/zitoc:CurrentJob/zitoc:Job",
      		    dataURL:"http://localhost/ziTocWS/JobDataAdapter.asmx"
      		});
      		
      		jobGrid.setDataSource(jobList);
      		jobGrid.fetchData();

      Comment


        #4
        If the web page and service are location on different ports on the same host, you would see a security exception like this. If you can move them to the same port, do that, otherwise you can use the HttpProxy Servlet included with the SmartClient Server to transparently "relay" the request.

        Comment


          #5
          >If the web page and service are location on different ports on the same host, you would see a security exception like this. If you can move them to the same port, do that

          Unfortunately, the web page and service are on different ports on the same host. I'm unsure what I can actually do about this. The SC pages need the built-in SC Server. I originally set the built-in SC Server to port "9090" as IIS7 already reserves port the built-in SC Server defaulted to. I cannot set both servers to the same port as they both (rightly) complain that the port is already in use and therefore unavailable. As I am using .NET .ASMX web services, they have to be referenced by IIS/ASP.NET. SmartClient is using its own server/port and both servers are on "LocalHost". Not sure what can be done in this regard.

          >otherwise you can use the HttpProxy Servlet included with the SmartClient Server to transparently "relay" the request.

          I have read up on "HttpProxy" in the documents but, it is not clear to me how I can use this servlet or the APIs to resolve the fact that both requirements are controlled by two different web servers on the same host (LocalHost) but both necessarily using different ports.

          I assume that there are other SmartClient developers that are using SC plus .NET Web Services/IIS on the same development machine so presumably, there is some kind of acceptable workaround.

          If you can advise how I can resolve this situation, it would be appreciated.

          Regards

          -H

          Comment


            #6
            The operation of the HttpProxy servlet ought to be transparent. Just change your target URL to include the port number, so "http://localhost:8080/whatever"

            Comment


              #7
              I specified the port number as follows:-

              Code:
               isc.DataSource.create({
                  ID:"jobList",
                  xmlNamespaces : {zitoc:"http://tempuri.org/"},
                  recordXPath:"/zitoc:CurrentJob/zitoc:Job",
                  dataURL:"http://localhost:80/ziTocWS/JobDataAdapter.asmx"
              });
              But still get the error specified below:-

              Access to restricted URI denied" code: "1012
              file:///C:/SmartClient_651_Evaluation/smartclientSDK/isomorphic/system/modules/ISC_Core.js
              Line 1026

              I have the SC server running against port "9090".

              Comment


                #8
                Strange. What does the address bar of your browser say at this point?

                Comment


                  #9
                  Browser bar says:-

                  http://localhost:9090/examples/gcw/DataBind.htm

                  Error Message in Firebug says:-

                  Access to restricted URI denied" code: "1012
                  http://localhost:9090/isomorphic/system/modules/ISC_Core.js
                  Line 1026

                  [Break on this error] _11.send(_7)}else{var _16=isc.rpc.addPar...;_11.open(_4,_16,!_9);if(_1.bypassCache)

                  Comment


                    #10
                    After the page errors, I was able to get the DevConsole to load and it reported:-

                    16:12:22.174:INFO:Log:initialized
                    16:12:23.348:INFO:Log:isc.Page is loaded
                    16:12:23.401:WARN:Log:[Exception... "Access to restricted URI denied" code: "1012" nsresult: "0x805303f4 (NS_ERROR_DOM_BAD_URI)" location: "http://localhost:9090/isomorphic/system/modules/ISC_Core.js Line: 1026"]

                    Comment


                      #11
                      Those errors pretty clearly indicate that the browser is blocking the request, believing it to be cross-domain. The proxy is not being used.

                      To force the proxy to be used, set useHttpProxy:true. There's a few places you could do this, but the easiest is the requestProperties parameter of fetchData ({ useHttpProxy:true }). If that solves it, you can set it centrally via operationBinding.requestProperties.

                      Comment


                        #12
                        >To force the proxy to be used, set useHttpProxy:true. There's a few places you could do this, but the easiest is the requestProperties parameter of fetchData ({ useHttpProxy:true }).

                        As indicated in the code below, the error occurs before fetchData() is called.

                        >If that solves it, you can set it centrally via operationBinding.requestProperties.

                        I have placed the assignment as shown in the DataSource.create() call below. I think I have done this correctly but could not find any concrete examples.

                        In any event, I am still getting the same error as before. What do you recommend?

                        Thanks.

                        Code:
                        	isc.ListGrid.create({
                        		    ID: "jobGrid",
                        		    width:"100%", alternateRecordStyles:true, showAllRecords:true
                        		});
                        		
                        		isc.DataSource.create({
                        		    ID:"jobList",
                        			operationBindings : [{ useHttpProxy:true }],
                        		    xmlNamespaces : {zitoc:"http://tempuri.org/"},  
                        		    recordXPath:"/zitoc:CurrentJob/zitoc:Job",
                        		    dataURL:"http://localhost:80/ziTocWS/JobDataAdapter.asmx"
                        		});
                        		
                        		jobGrid.setDataSource(jobList);
                        		jobGrid.fetchData({ useHttpProxy:true });  // Too late here - there error occurs in the DataSource.create

                        Comment


                          #13
                          Why do you believe it happens during DataSource.create()? That doesn't happen in my test, and isn't very plausible - create() does nothing but create a JavaScript object in this case, no access to the DOM or the network.

                          Corrected code below.

                          Code:
                          	
                                          isc.ListGrid.create({
                          		    ID: "jobGrid",
                          		    width:"100%", alternateRecordStyles:true, showAllRecords:true
                          		});
                          		
                          		isc.DataSource.create({
                          		    ID:"jobList",
                          		    operationBindings : [
                                                   { operationType:"fetch", 
                                                      requestProperties:{useHttpProxy:true }
                                                   }
                                              ],
                          		    xmlNamespaces : {zitoc:"http://tempuri.org/"},  
                          		    recordXPath:"/zitoc:CurrentJob/zitoc:Job",
                          		    dataURL:"http://localhost:80/ziTocWS/JobDataAdapter.asmx"
                          		});
                          		
                          		jobGrid.setDataSource(jobList);
                          		jobGrid.fetchData(null, null, { useHttpProxy:true });

                          Comment


                            #14
                            >Why do you believe it happens during DataSource.create()

                            Because when I tried to step through the code using Firebug, the moment I tried to step over the create(), the error occured.

                            Happy to report that your sample code has made the error go away. Thanks for that. However, all that I see in the browser is an empty grid and a message saying:-

                            "Loading data..."

                            I checked the DevConsole log and it states the following:-

                            22:57:24.460:INFO:Log:initialized
                            22:57:25.784:INFO:Log:isc.Page is loaded
                            22:57:26.029:XRP7:WARN:parseXML:Error parsing XML: XML Parsing Error: mismatched tag. Expected: </br>.
                            Location: http://localhost:9090/examples/gcw/DataBind.htm
                            Line Number 61, Column 19: </span>
                            ------------------^

                            I'm afraid I have to plead ignorance at this stage because I have no idea what the above message really means or where it is occuring.

                            Does the above provide any clues?

                            Comment


                              #15
                              If useHttpProxy fixes the problem, the error was not on create(). You can prove this yourself by removing the useHttpProxy setting in the DataSource, which is currently redundant with the one passed to fetchData(). Firebug may have line numbers wrong, not sure.

                              That error message means your server is not returning valid XML, instead, judging by the <br> it's likely to be some kind of error page. You can look either in the server-side logs, the "RPC" tab in the Developer Console or Firebug to see what was returned.

                              Comment

                              Working...
                              X