WCF service With composite C1

Topics: General
Mar 22, 2011 at 8:59 AM

How to use composite in WCF service 

Coordinator
Mar 22, 2011 at 9:54 AM

Typically you just "write the code" like you would on any ASP.NET 4 based website - I'm not aware of anything preventing you from consuming or exposing WCF services.

Also take a look at the OData sample at http://docs.composite.net/OData - I guess this is related. It shows how you can expose your data via OData (including dynamically defined types) without implicitly writing code for each type.

Mar 22, 2011 at 10:07 AM

Hi, 

Thanks for the instant reply. Actually i have made simple WCF service inside Composite and consumed it from Some User Control. It is quite straight froward. But i am interested about using Composite inner functionality in WCF service. For example we have news package having latest news and acrhive news functionality, i want to use those functionality in WCF service but i could not access those.

do you have idea, please i am interested to hear it.

Thanks

Coordinator
Mar 22, 2011 at 10:26 AM

If you need access to the raw news data, check out the API for Composite C1 - the DataConnection class will enable you to query and manipulate data.

Sample code:

using System.Collections.Generic;
using System.Linq;
using Composite.Data;

// ...
      using (DataConnection connection = new DataConnection())
      {
        var titles = from news in connection.Get<Composite.News.NewsItem>()
                     select news.Title;
    
        // ...

      }            


Mar 22, 2011 at 11:58 AM

Thanks i did, Exactly it works fine for normal function while put it inside WCf function it doesnot work.

 

I have made function like this

 

  public List<string> GetCustomizeNews()
        {
       

            List<string> li = new List<string>();
            using (DataConnection connection = new DataConnection())
            {
                var titles = from news in connection.Get<Composite.News.NewsItem>()
                             select news.Title;

                foreach (string title in titles)
                {
                    li.Add(title);
                }
                return li;
            }

        }

While consuming this function from service client following error occurs:
"Input string was not in a correct format."

What could be the problem?

Coordinator
Mar 22, 2011 at 12:03 PM

Is there a stack trace?

Mar 22, 2011 at 12:04 PM

try setting language and publication scope explicitly on your dataconnection... when your not accessing a Composite Page, it won't be set by the system and will use default values.

Mar 22, 2011 at 12:08 PM

Yes,

 

There is following error message

The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.

 

The detail of Stack trace as belows

[FaultException: The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the  configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.]
   System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +9464367
   System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) +345
   GRServiceReference.IGRService.GetCustomizeNews() +0
   GRServiceReference.GRServiceClient.GetCustomizeNews() in c:\Users\bal\AppData\Local\Temp\Temporary ASP.NET Files\root\63d7793e\6c36f63b\App_WebReferences.lidold-f.0.cs:174
   TestiUC.Page_Load(Object sender, EventArgs e) in c:\7-Composite Devemix\TestC1\Website\TestiUC.ascx.cs:14
   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
   System.Web.UI.Control.OnLoad(EventArgs e) +91
   System.Web.UI.Control.LoadRecursive() +74
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Control.LoadRecursive() +146
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2207

But while using it from normal function with out WCF service it works fine.

Thanks

Mar 22, 2011 at 12:11 PM

no, i remember what it mostly likely is... you need to create an instance of the DataScope class and dispose it again when your request is done... in your above example you can do this

public List<string> GetCustomizeNews()
        {
            List<string> li = new List<string>();
            using (var scope = new DataScope()) {
               using (DataConnection connection = new DataConnection())
               {
                   var titles = from news in connection.Get<Composite.News.NewsItem>()
                             select news.Title;

                   foreach (string title in titles)
                   {
                       li.Add(title);
                   }
                   return li;
               }
            }
        }
All the examples on Composite.net expects a datascope to be present, which isn't the case when your code is not invoked during a normal composite page request.

Mar 22, 2011 at 12:21 PM

Thanks

But still having some problem

 

 

Compilation Error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

Compiler Error Message: CS1729: 'Composite.Data.DataScope' does not contain a constructor that takes 0 arguments

Source Error:

Line 52:         {
Line 53:             List li = new List();
Line 54:             using (var scope = new DataScope())
Line 55:             {
Line 56:
Coordinator
Mar 22, 2011 at 12:31 PM

@shresthabal Looks like your stack trace is for the WCF client, and it is basically saying "WCF server threw and exception - do (actions) to get exception details". So the stack trace is not really saying much about the core problem.

Try one of the following:

  1. Try burningice's suggestion - new up the DataConnection class with a CultureInfo (for the language that data should belong to) and a publication scope (selecting published data).
  2. If this does not solve your issue, look the the exception info - it contains hints on how you can get "the real exception details". With those details (the exception of the failing WCF service and not the calling client) there is something more to work with

What ever you find out please keep us posted :-)

Mar 22, 2011 at 12:33 PM

Of course you need to use the constructor that is appropriate for you... if you want only published content in English you use

new DataScope(DataScopeIdentifier.Public, new CultureInfo("en-US"))

Coordinator
Mar 22, 2011 at 12:39 PM

The complete code would then be:

public List<string> GetCustomizeNews()
{
  List<string> li = new List<string>();
  using (DataConnection connection = new DataConnection(PublicationScope.Published, new CultureInfo("en-US")))
  {
    var titles = from news in connection.Get<Composite.News.NewsItem>()
                     select news.Title;

    foreach (string title in titles)
    {
      li.Add(title);
    }
    return li;
  }
}

(you should change "en-US" with the culture name relevant to your data).

Mar 22, 2011 at 12:47 PM

Thanks 

But still it didnot work

 

I have this code snippet

   public List<string> GetCustomizeNews()
        {
            
            List<string> li = new List<string>();
            DataConnection conn = new DataConnection();
           // DataScopeIdentifier dsi = new DataScopeIdentifier();
            using (var scope = new DataScope(DataScopeIdentifier.Public, new CultureInfo("fi-FI")))
            {
                using (DataConnection connection = new DataConnection())
                {
                    var titles = from news in connection.Get<Composite.News.NewsItem>()
                                 select news.Title;

                    foreach (string title in titles)
                    {
                        li.Add(title);
                    }
                    return li;
                }
            }
        }

It gave following error,

 

System.FormatException was unhandled by user code
  Message=Input string was not in a correct format.
  Source=mscorlib
  StackTrace:
       at System.Text.StringBuilder.AppendFormat(IFormatProvider provider, String format, Object[] args)
       at System.String.Format(IFormatProvider provider, String format, Object[] args)
       at System.String.Format(String format, Object[] args)
       at Composite.Core.Threading.ThreadDataManager.GetCurrentNotNull()
       at Composite.Data.DataFacadeImpl.get_DataInterceptors()
       at Composite.Data.DataFacadeImpl.GetData[T](Boolean useCaching, IEnumerable`1 providerNames)
       at Composite.Data.DataFacade.GetData[T](Boolean useCaching, IEnumerable`1 providerNames)
       at Composite.Data.DataFacade.GetData[T]()
       at Composite.Core.Implementation.DataConnectionImplementation.Get[TData]()
       at Composite.Data.DataConnection.Get[TData]()
       at GRService.GetCustomizeNews() in c:\7-Composite Devemix\TestC1\Website\App_Code\GRService.cs:line 61
       at SyncInvokeGetCustomizeNews(Object , Object[] , Object[] )
       at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
       at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
  InnerException: 

Mar 22, 2011 at 4:30 PM

This is interesting... how are you exposing your WCF service? if through IIS, are you using asp.net compatibility or not?

Mar 23, 2011 at 6:56 AM

@burningice No i have not use IIS. I have use development server to host it.

the hosted service address is like as follows.

http://localhost:36859/WCF/GRService.svc

Coordinator
Mar 23, 2011 at 7:48 AM
Edited Mar 23, 2011 at 7:55 AM

The following code should work

public List<string> GetCustomizeNews()
{
  using (Composite.Core.Threading.ThreadDataManager.EnsureInitialize())
  using (var conn = new DataConnection(PublicationScope.Published, new CultureInfo("fi-FI")))
  {
    var titles = from news in conn.Get<Composite.News.NewsItem>()
                     select news.Title;

    return titles.ToList();
  }
}

Class ThreadDataManager  supposed  to raise the following exception text:

 

ThreadDataManager hasn't been initialized in the current thread. You probably have forgotten to use Composite.Core.Threading.ThreadDataManager.EnsureInitialize() call on a custom created thread.

Example of usage:

using(Composite.Core.Threading.ThreadDataManager.EnsureInitialize())

{

  // Code that works with C1 data layer goes here  

  .....

}

 

but there's a small bug in code that prevented it, and you got this not very informative FormatException. Will be fixed with in the next commit

Mar 23, 2011 at 8:00 AM

Thank u very much, Now it works, But its wired that we have to add using(Composite.Core.Threading.ThreadDataManager.EnsureInitialize()) this line and there in no any information about this. 

 

Anyway Cheers!

Coordinator
Mar 23, 2011 at 8:23 AM

@shresthabal with the fix mentioned by napernik the exception will be pretty informative. Also, I logged a task for adding info about the ThreadDataManager class to http://api.composite.net/

Just a short description of the ThreadDataManager; this class coordinate data connections and ensure that multiple requests to SQL Server will reuse the same sql connection, allowing transactions to run without the use of MSDTC (MSDTC can be a complete bitch in relation to configuration/security).

Mar 23, 2011 at 10:41 AM
Edited Mar 23, 2011 at 10:57 AM

And maybe more importanly, WHY you need this is because all the documentation in Composite.net assumes that you write code running in the context of a normal Composite Page request, and when you do that there are some modules and handlers that will make sure to initialize the ThreadDataManager for you. Also if your hosting your WCF service in a context where asp.net compatibility is disabled, you can't access HttpContext.Current which ThreadDataManager also tries to use when you're running your code on a webpage.

Mar 23, 2011 at 11:51 AM

I was testing WCF service in Composite C1 for exploring probability of using it from various dimension.

 There can be some situation where WCF service is better for use while developing application. It is always better to have wide range of probability for developer :)