+1-888-365-2779
Try Now
More in this section

Forums / Sitefinity SDK / Consuming SF 4 REST service

Consuming SF 4 REST service

20 posts, 0 answered
  1. SolarX
    SolarX avatar
    14 posts
    Registered:
    24 Oct 2006
    08 Sep 2010
    Link to this post

    Hi,

    I’m having a hard time consuming the SF4 webservices.

     

    Could you please be so kind to provide a code snippet that connects to “services/pages/PagesService.svc” and retrievs a “CollectionContext<PageViewModel>” from the methode “GetPagesAsTree”.

     

    I do receive a 405 error. I’m also not quite sure how to authenticate this request with the right user credentials.

    A code-snippet would be very helpful as I’m stuck with this basic step..:(

     

    What I’m trying to do: Connect to SF4 webservices from an .net windows-forms application which will be used as a migration tool for our old CMS.

    Thanx

  2. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    19 Sep 2016
    08 Sep 2010
    Link to this post
    Hello SolarX,

    GetPagesAsTree uses POST method to retrieve the data. GetPagesAsTree returns xml or jason that you should parse. You can use /PagesService.svc/xml/ which will return the data as  XML. You have to make web request where the method type is POST.(WebRequest.Create)

    By default the Get method is processed without authentication when you are not trying to create, delete or update an item.. Please check whether you make the proper POSt request. You can use GetPages which also returns all pages and parent IDs so you can make the relation easily.

    Best wishes,
    Ivan Dimitrov
    the Telerik team

    Check out Telerik Trainer, the state of the art learning tool for Telerik products.
  3. SolarX
    SolarX avatar
    14 posts
    Registered:
    24 Oct 2006
    09 Sep 2010
    Link to this post
    Thank you for your quick answer.
    Here is the code I'm using in a test project. When I call GetPagesAsTree at the end I get an "405 method not allowed" exception. Maybe my usage of the parameters is wrong.

    private void CallService()
            {
                BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
                EndpointAddress address = new EndpointAddress("http://ffm-srv-ext-2a/SF4B/Sitefinity/services/pages/PagesService.svc/xml/");

                ChannelFactory<IPagesService> factory =
                    new ChannelFactory<IPagesService>(binding, address);
                factory.Open();

                IPagesService channel = factory.CreateChannel();

                string[] leafIds = new string[10];
                CollectionContext<PageViewModel> pageTree = channel.GetPagesAsTree(leafIds, "", 10, 10, 10, 10, "");

                factory.Close();
            }
  4. Radoslav Georgiev
    Radoslav Georgiev avatar
    3370 posts
    Registered:
    01 Feb 2016
    09 Sep 2010
    Link to this post
    Hello SolarX,

    If you are using IIS 7.5 make sure to disable the WebDAV module. It restricting put and delete methods of webservices. You can check this article for more information.

    Regards,
    Radoslav Georgiev
    the Telerik team

    Check out Telerik Trainer, the state of the art learning tool for Telerik products.
  5. SolarX
    SolarX avatar
    14 posts
    Registered:
    24 Oct 2006
    09 Sep 2010
    Link to this post
    Hi,

    I've changed the web.config accordingly. Anyway WEBDav feature isn't installed on the server at all.
    Still getting the same error.

    Thanx for your help!
  6. Radoslav Georgiev
    Radoslav Georgiev avatar
    3370 posts
    Registered:
    01 Feb 2016
    09 Sep 2010
    Link to this post
    Hi SolarX,

    The problem is not coming from the parameters used. It is coming from the HttpBinding used. Try this :
    WebHttpBinding binding = new WebHttpBinding();
    EndpointAddress address = new EndpointAddress("http://localhost:4000/Sitefinity/services/pages/PagesService.svc/");
    ChannelFactory<IPagesService> factory =
        new ChannelFactory<IPagesService>(binding, address);
    factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
    factory.Open();
    IPagesService channel = factory.CreateChannel();
    WcfPageContext page = channel.GetPage("35bb4ae9-d916-49f7-80db-cf8823746105", null, false);

    Or bellow is an alternative approach you can use to call the services:
    var request1 = (HttpWebRequest)WebRequest.Create("http://localhost:4000/Sitefinity/Services/Pages/PagesService.svc/tree/");
            request1.Method = "POST";
            string postData = @"[""365af67c-a4a5-4552-83d9-e5ceb2dcbc06""]";
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);
            // Set the ContentType property of the WebRequest.
            request1.ContentType = "application/json";
            // Set the ContentLength property of the WebRequest.
            request1.ContentLength = byteArray.Length;
            // Get the request stream.
            Stream dataStream = request1.GetRequestStream();
            // Write the data to the request stream.
            dataStream.Write(byteArray, 0, byteArray.Length);
            // Close the Stream object.
            dataStream.Close();
            // Get the response.
            WebResponse response1 = request1.GetResponse();
            // Display the status.
            Console.WriteLine(((HttpWebResponse)response1).StatusDescription);
            // Get the stream containing content returned by the server.
            dataStream = response1.GetResponseStream();
            // Open the stream using a StreamReader for easy access.
            StreamReader reader = new StreamReader(dataStream);
            // Read the content.
            string responseFromServer = reader.ReadToEnd();
            // Display the content.
            Console.WriteLine(responseFromServer);
            // Clean up the streams.
            reader.Close();
            dataStream.Close();
            response1.Close();

    Regards,
    Radoslav Georgiev
    the Telerik team

    Check out Telerik Trainer, the state of the art learning tool for Telerik products.
  7. SolarX
    SolarX avatar
    14 posts
    Registered:
    24 Oct 2006
    09 Sep 2010
    Link to this post
    Great. That solved the 405 error !! Thanx :)

    I do now get an "Internal Server Error" exception when calling "GetPagesAsTree". From the server log I can see it should be a problem with the parameters I supply. Could you please provide further information about the required parameters.

    Thank you very much !!

    This is from the server app log:

    Exception information:

    Exception type: ArgumentNullException

    Exception message: Value cannot be null.

    Parameter name: g

     

    Request information:

    Request URL: http://ffm-srv-ext-2a/SF4B/Sitefinity/services/pages/PagesService.svc/xml/tree/?provider=&nodesLimit=10&perLevelLimit=10&perSubtreeLimit=10&subtreesLimit=10&root=

    Request path: /SF4B/Sitefinity/services/pages/PagesService.svc/xml/tree/

    User host address: 10.73.11.73

    User: Anonymous

    Is authenticated: False

    Authentication Type: Sitefinity

    Thread account name: IIS APPPOOL\DefaultAppPool

     

    Thread information:

    Thread ID: 5

    Thread account name: IIS APPPOOL\DefaultAppPool

    Is impersonating: False

    Stack trace: at System.Guid..ctor(String g)

    at Telerik.Sitefinity.Modules.Pages.Web.Services.PagesService.GetPagesAsTreeInternal(String[] leafIds, String provider, Int32 nodesLimit, Int32 perLevelLimit, Int32 perSubtreeLimit, Int32 subtreesLimit, String root)

    at SyncInvokeGetPagesAsTreeInXml(Object , Object[] , Object[] )

    at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)

    at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)

    at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)

    at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)

    at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

     

     

    Custom event details:

  8. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    19 Sep 2016
    09 Sep 2010
    Link to this post
    Hi SolarX,

    The  error is thrown, because one of the parameters you pass is not correct or null( but it should not be a null). The stack does not contain which of your parameters is the problematic one, but I suppose that this is leafIds.

    Greetings,
    Ivan Dimitrov
    the Telerik team

    Check out Telerik Trainer, the state of the art learning tool for Telerik products.
  9. SolarX
    SolarX avatar
    14 posts
    Registered:
    24 Oct 2006
    10 Sep 2010
    Link to this post
    Hi,

    that is what I thought.
    Since the parameters aren't documented yet, could you please provide a specific example for "GetPagesAsTree".
    I really need to get further with my project. What I need is to get a hierarchical list of all pages (structure of the site). Besides the parameters, is "GetPagesAsTree" the right method to achieve that?

    Thanx,

    Martin
  10. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    19 Sep 2016
    10 Sep 2010
    Link to this post
    Hi SolarX,

    GetPagesAsTree accepts the following parameters

    leafIds - The ids of the leaf pages - if empty array an error is thrown
    provider - provider that will be used - if null the default one is used
    nodesLimit - limit the number of nodes  - int value / 0 gets all
    perLevelLimit - limit level nodes - int value / 0 gets all
    subtreesLimit - limit the sub trees  - int value  / 0 gets all
    root - should be null to get all pages - type - string.


    The code that we sent you is a working sample which returns the data in JSON and we get the response as stream, but you could parse it as xml or directly use GetPagesAsTreeInXml



    Sincerely yours,
    Ivan Dimitrov
    the Telerik team

    Check out Telerik Trainer, the state of the art learning tool for Telerik products.
  11. Dean
    Dean avatar
    5 posts
    Registered:
    15 May 2008
    16 May 2011
    Link to this post
    What file do we add your WebHttpBinding or HttpWebRequest code to.  Can you give instructions where to create the file and what to call it.
  12. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    19 Sep 2016
    16 May 2011
    Link to this post
    Hi Dean,

    It depends on from where you want to call the service - user control, custom control, page etc.
    The better option is using Sys.Net.WebRequest(); to call the service.

    All the best,
    Ivan Dimitrov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get now >>

  13. Dean
    Dean avatar
    5 posts
    Registered:
    15 May 2008
    16 May 2011
    Link to this post
    Ivan

    If we were going to use the Sys.Net.WebRequest(); to call the service, do you have sample code and how to implement it.

    With Sitefinity 4.x, are all of the webpages stored in sql?
  14. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    19 Sep 2016
    16 May 2011
    Link to this post
    Hi Dean,

    This is a standard MS AJAX call.

    sample

           var wRequest = new Sys.Net.WebRequest();
            wRequest.set_url(this._generateNonBinderUrl(url, urlParams, keys));
            wRequest.set_httpVerb('POST');
            this._applyLocalizationHeaders(wRequest);

            if (data) {
                var postData = Sys.Serialization.JavaScriptSerializer.serialize(data);
                wRequest.set_body(postData);
                wRequest.get_headers()["Content-Type"] = "application/json";
            }
            else {
                alert('POST method cannot be invoked without the data');
                return;
            }

            var delegates = { Success: successDelegate, Failure: failureDelegate, Caller: caller, Context: context };
            wRequest.set_userContext(delegates);
            wRequest.add_completed(this.NonBinderCallbackDelegate);
        },

    Best wishes,
    Ivan Dimitrov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get now >>

  15. Dean
    Dean avatar
    5 posts
    Registered:
    15 May 2008
    16 May 2011
    Link to this post
    Thanks again Ivan.

    With Sitefinity 4.x, are all of the webpages stored in sql.  Is there a main page that we can edit to consume this code?
  16. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    19 Sep 2016
    16 May 2011
    Link to this post
    Hi Dean,

    You can create a simple user control where you trigger the service call with a button.

    All the best,
    Ivan Dimitrov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get now >>

  17. Ray
    Ray avatar
    15 posts
    Registered:
    09 Jul 2008
    18 May 2011
    Link to this post
    The information in this thread has been really helpful so far but I can't seem to find a  way to authenticate an application outside of the browser/web application to use the REST Services. Normal authentication techniques with WCF don't seem to work. Could some sort of example of this be supplied. Thanks.
  18. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    19 Sep 2016
    19 May 2011
    Link to this post
    Hello Ray,

    Check if this helps. Recently we found some issues related to the logout of the users in this scenario, but we are working on the issue.

    Greetings,
    Ivan Dimitrov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get now >>

  19. Greg
    Greg avatar
    1 posts
    Registered:
    13 Jul 2011
    11 Aug 2011
    Link to this post
    I worked up a workaround for the WCF services and authentication from an external application with regard to authenticating a user with the Sitefinity Users.svc service and then subsequently accessing resources that require an authenticated user (retrieving a page from PagesService.svc, for example).

    The issue seemed to be that between WCF calls, the authorization cookie returned with the AuthenticateUser method is not stored, and thus not sent when making the next call to another service.

    Based on this blog entry, http://megakemp.wordpress.com/2009/02/06/managing-shared-cookies-in-wcf/, I repurposed that project into small WCF behavior extension (almost no changes...) that stores the cookies and injects it into any of the next WCF service calls which utilize that behavior.

    class PersistantCookieBehaviorExtensionElement : BehaviorExtensionElement
    {
        protected override object CreateBehavior()
        {
            return new PersistantCookieBehavior();
        }
     
        public override Type BehaviorType
        {
            get { return typeof(PersistantCookieBehavior); }
        }
    }
     
    class PersistantCookieBehavior : IEndpointBehavior
    {
        public void Validate(ServiceEndpoint endpoint)
        {
            return;
        }
     
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
            return;
        }
     
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            return;
        }
     
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(PersistantCookieClientMessageInspector.Instance);
        }
    }
     
    public class PersistantCookieClientMessageInspector : IClientMessageInspector
    {
        private static PersistantCookieClientMessageInspector instance;
        private string persistedCookie;
     
        private PersistantCookieClientMessageInspector() { }
     
        public static PersistantCookieClientMessageInspector Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new PersistantCookieClientMessageInspector();
                }
     
                return instance;
            }
        }
     
        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            var httpResponse =
                reply.Properties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty;
     
            if (httpResponse != null)
            {
                string cookie = httpResponse.Headers[HttpResponseHeader.SetCookie];
     
                if (!string.IsNullOrEmpty(cookie))
                {
                    this.persistedCookie = cookie;
                }
            }
        }
     
        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            if (!request.Properties.ContainsKey(HttpRequestMessageProperty.Name))
            {
                request.Properties.Add(HttpRequestMessageProperty.Name, new HttpRequestMessageProperty());
            }
     
            var httpRequest = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
            httpRequest.Headers.Add(HttpRequestHeader.Cookie, this.persistedCookie);
     
            return null;
        }
    }

    Since I was using a WPF app, I configured the WCF behaviors and endpoints as:

    <system.serviceModel>
      <extensions>
        <behaviorExtensions>
          <add name="PersistantCookieBehavior" type="MyAssembly.PersistantCookieBehaviorExtensionElement, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        </behaviorExtensions>
      </extensions>
     
      <behaviors>
        <endpointBehaviors>
          <behavior name="CookieBehaviorConfig">
            <PersistantCookieBehavior />
          </behavior>
        </endpointBehaviors>
      </behaviors>
     
      <bindings>
        <webHttpBinding>
          <binding name="PagesServiceBinding" maxReceivedMessageSize="1024000000" />
        </webHttpBinding>
      </bindings>
       
      <client>
        <endpoint name="UserServiceEndpoint"
                  address="http://localhost/sitefinity/services/security/Users.svc/"
                  binding="webHttpBinding"
                  behaviorConfiguration="CookieBehaviorConfig"
                  contract="Telerik.Sitefinity.Security.Web.Services.IUsers" />
        <endpoint name="PagesServiceEndpoint"
                  binding="webHttpBinding"
                  bindingConfiguration="PagesServiceBinding"
                  behaviorConfiguration="CookieBehaviorConfig"
                  contract="Telerik.Sitefinity.Modules.Pages.Web.Services.IPagesService" />
      </client>
    </system.serviceModel>

    Then you can very simply call the User service to authenticate your user, the cookie is persisted between WCF calls, and used when calling the PagesService:

    var usersService = new WebChannelFactory<IUsers>("UserServiceEndpoint");
    var usersChannel = usersService.CreateChannel();
    var auth = usersChannel.AuthenticateUser(new Telerik.Sitefinity.Security.Credentials() { UserName = "username", Password = "password", Persistent=true });
     
    var pagesService = new WebChannelFactory<IPagesService>("PagesServiceEndpoint");
    var pagesChannel = pagesService.CreateChannel();
    var page = pagesChannel.GetPage("096fd910-40d7-4887-a9e6-fff465920774", null, false);

    Note that if the user is already authenticated to the site when attempting to this call, the authentication will fail, so you'll need to log the user out. That part of the example is an exercise left to the developer.

    Hopefully this helps someone else, as I've spent the last few days attempting to work with the web services to enable custom fields on pages, so far to no avail.
  20. Ivan Dimitrov
    Ivan Dimitrov avatar
    16072 posts
    Registered:
    19 Sep 2016
    12 Aug 2011
    Link to this post
    Hello Greg,

    Actually this is the only way for now to authenticate, because we don't have a specific service that you can use to authenticate a user or an existing service where you can pass the parameters.

    You might find this post ( call service from javascript)useful.

    Best wishes,
    Ivan Dimitrov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get now >>

20 posts, 0 answered