locked
Multiple End points - System.DataServices.DataService<T> and System.ServiceModel.ServiceContract RRS feed

  • Question

  • Hi,

    I have an existing WCF Data Service which is currently configured to work with System.DataServices.DataService<T> however when I add System.ServiceModel.ServiceContract it has issues.

    Here's my code

    ITestService.cs

    using System.Collections.Generic;
    using System.ServiceModel;
    
    namespace TestService
    {
        [ServiceContract]
        public interface ITestService
        {
            [OperationContract]
            IEnumerable<DataType1> GetActiveDataType1();
    
            [OperationContract]
            string GetDataType1Name(string Name, string ID, string ID2, bool htmlFormat = false);
        }
    }

    TestService.svc.cs

    using System.Collections.Generic;
    using System.Data.Services;
    using System.Data.Services.Common;
    using System.Linq;
    using System.ServiceModel.Web;
    
    namespace TestService
    {
        [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
        public class TestService : DataService<TestDataEntities>, ITestService
        {
            protected override TestDataEntities CreateDataSource()
            {
                var context = base.CreateDataSource();
                context.Configuration.ProxyCreationEnabled = false;
                return context;
            }
    
            [WebGet]
            public IEnumerable<DataType1> GetActiveDataType1()
            {
                var context = CurrentDataSource;
    
                //return IEnumerable result
            }
    [WebGet]
            public string GetDataType1Name(string Name, string ID, string ID2, bool htmlFormat = false)
            {
                var context = CurrentDataSource;
                //return name;
            }

    Web.config

    <?xml version="1.0"?>
    <configuration>
      <connectionStrings>
        <add name="TestDataEntities" connectionString="Data Source=SomeSQL; Integrated Security=SSPI; database=Test; MultipleActiveResultSets=True" providerName="System.Data.SqlClient"/>
      </connectionStrings>
      
    
      <system.web>
        <authentication mode="Windows"/>
        <authorization>
          <allow users="*"/>
        </authorization>
        <customErrors mode="Off"/>
    	  <compilation debug="true" targetFramework="4.5"/>
    	  <pages controlRenderingCompatibilityVersion="4.0"/>
      </system.web>
      <system.serviceModel>
        <behaviors>
          <serviceBehaviors>
            <behavior>
              
              <serviceMetadata httpGetEnabled="false"/>
              
              <serviceDebug includeExceptionDetailInFaults="false"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>
      </system.serviceModel>
      <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
      </system.webServer>
    </configuration>

    This configuration works fine if I'm just using System.DataServices.DataService<T>. 

    When I try running the service, it throws this error: 

    Service 'TestService' implements multiple ServiceContract types, and no endpoints are defined in the configuration file. WebServiceHost can set up default endpoints, but only if the service implements only a single ServiceContract. Either change the service to only implement a single ServiceContract, or else define endpoints for the service explicitly in the configuration file.

    I tried defining the end points as follows in the Web.config:

    <?xml version="1.0"?>
    <configuration>
      <connectionStrings>
        <add name="TestDataEntities" connectionString="Data Source=SomeSQL; Integrated Security=SSPI; database=Test; MultipleActiveResultSets=True" providerName="System.Data.SqlClient"/>
      </connectionStrings>
      <system.web>
        <authentication mode="Windows"/>
        <authorization>
          <allow users="*"/>
        </authorization>
        <customErrors mode="Off"/>
        <compilation debug="true" targetFramework="4.5"/>
        <pages controlRenderingCompatibilityVersion="4.0"/>
      </system.web>
      <system.serviceModel>
    	  <services>
    		  <service name="TestService.TestService">
    			  <endpoint binding="webHttpBinding" contract="TestService.ITestService" behaviorConfiguration="web" />
    						
    		  </service>
    	  </services>
        <behaviors>
    		<endpointBehaviors>
    			<behavior name="web">
    				<webHttp/>
    			</behavior>
    		</endpointBehaviors>
          <serviceBehaviors>
            <behavior>
              <serviceMetadata httpGetEnabled="false"/>
              <serviceDebug includeExceptionDetailInFaults="false"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>
      </system.serviceModel>
      <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
      </system.webServer>
    </configuration>

    The error I get with this configuration is "Endpoint not found".

    Please help :)

    Thanks


    • Edited by Moneka Wednesday, May 28, 2014 7:53 PM
    Wednesday, May 28, 2014 7:52 PM

Answers

  • >>However when I try using it in Linqpad or in the application with linq it doesn't recognize the method.

    No, you cannot do that with the WCF + EF application, we can use LINQ method because when we add a reference for the WCF Data Service, it will install the Microsoft.Data.Services.Client dll, these linq methods are under this namespace. And I read your original post, I am confused why you do not use the WCF Data Service which can completely do that you want:

    1.it gives us the capability of having access to all of the entities from the service.

    2. What I am trying to do is maintain that piece and also add in a service method (or 2) that I could expose through the service and consume in other applications.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Tuesday, June 3, 2014 8:21 AM
    Moderator

All replies

  • Hello Moneka,

    In actual, you are working with WCF + Entity Framework rather than WCF Data Service. In WCF + Entity Framework, we do not need to let the TestService inherent DataService<TestDataEntities>, it just needs to implement the interface. In WCF + Entity Framework, we access the data as:

    public class ProductService : IProductService
    
        {
    
            public Product GetProduct(int id)
    
            {
    
                NorthwindEntities context = new NorthwindEntities();
    
                var productEntity = (from p
    
                                     in context.ProductEntities
    
                                     where p.ProductID == id
    
                                     select p).FirstOrDefault();
    
               if (productEntity != null)
    
                   return TranslateProductEntityToProduct(productEntity);
    
               else
    
                   throw new Exception("Invalid product id");
    
            }
    
            private Product TranslateProductEntityToProduct(
    
                  ProductEntity productEntity)
    
           {
    
                 Product product = new Product();
    
                 product.ProductID = productEntity.ProductID;
    
                 product.ProductName = productEntity.ProductName;
    
                 product.QuantityPerUnit = productEntity.QuantityPerUnit;
    
                 product.UnitPrice = (decimal)productEntity.UnitPrice;
    
                 product.Discontinued = productEntity.Discontinued;
    
                 return product;
    
           }
    
    }
    

    The NorthwindEntities object inherents from DbContext. For details, you can refer to this link:

    http://www.codeproject.com/Articles/127395/Implementing-a-WCF-Service-with-Entity-Framework

    And for the WCF Data Service, it is simpler, we just need to add the WCF Data Service template:

    It will create the server class inherited from DataService<TestDataEntities> automatically. For details, you can refer to this link:

    http://msdn.microsoft.com/en-us/library/dd728275(v=vs.110).aspx

    Being careful if you are using Entity Framework 6, it needs us to modify the code a bit as described here:

    http://blogs.msdn.com/b/odatateam/archive/2013/10/02/using-wcf-data-services-5-6-0-with-entity-framework-6.aspx

    If I misunderstand, please let me know.

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, May 29, 2014 2:08 AM
    Moderator
  • Hi Fred,

    Thanks for responding!

    Actually I need to inherit from DataServices <T> - it gives us the capability of having access to all of the entities from the service. What I am trying to do is maintain that piece and also add in a service method (or 2) that I could expose through the service and consume in other applications. However I'm pretty stumped on how to do that...

    Any help is deeply appreciated!

    Thanks,

    Moneka

    Thursday, May 29, 2014 2:58 PM
  • Hi,

    Okey, so you are trying to invoke Data Services with ServiceContract, then you may need to define an explicit endpoint as described here:

    http://stackoverflow.com/questions/2542119/how-to-disable-authentication-schemes-for-wcf-data-services

    In actual, you can also write your custom operations in WCF Data Services:

    http://msdn.microsoft.com/en-us/library/cc668788(v=vs.110).aspx

    Update:

    After studying for a while, finally it seems that you need to add a correct enpoint in your config file because with your idea, I got it. Here is the Sever side code:

    The interface:

    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
        [ServiceContract]
        public interface IProductService
        {
            [OperationContract]
            IEnumerable<Order> GetOrder();
        }

    The .svc:

     public class ProductService : DataService<DFDBEntities>, IProductService
        {
            [WebGet]
            public IEnumerable<Order> GetOrder()
            {
                var context = new DFDBEntities();
    
                var result = context.Orders;
    
                return result.AsEnumerable();
    
                //return IEnumerable result
            }
        }

    I set the ProxyCreationEnabled to false in the constructor since I notice that the overriden method does not help.

    The client code:

    class Program
        {
            static void Main(string[] args)
            {
                ProductService.ProductServiceClient client = new ProductService.ProductServiceClient();
    
                IEnumerable<ProductService.Order> orders = client.GetOrder();
            }
        }

    It can get data successfully.

    And the config file:

    In appsetting section, add the baseAddress key and its value.

    <appSettings>
        <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
        <add key="baseAddress" value="http://localhost:43537/Server20140529/ProductService" />
      </appSettings>

    In system.serviceModel section, adding endpoint as:

    <system.serviceModel>
        <services>
          <!-- This section is optional with the default configuration introduced
             in .NET Framework 4. -->
          <service name="Server20140529.ProductService">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:43537/Server20140529/ProductService"/>
              </baseAddresses>
            </host>
            <endpoint address=""
                      binding="wsHttpBinding"
                      contract="Server20140529.IProductService" />
          </service>
        </services>
    
        <behaviors>
          <serviceBehaviors>
            <behavior>
              <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
              <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
              <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
              <serviceDebug includeExceptionDetailInFaults="false" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
        <protocolMapping>
          <add binding="basicHttpsBinding" scheme="https" />
        </protocolMapping>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
      </system.serviceModel>

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.





    Friday, May 30, 2014 6:50 AM
    Moderator
  • Hi Fred,

    Thanks for your response!

    You are definitely right! It's my configuration that's the problem.

    I tried using what you specified however I am getting a blank page when I try to browse to the service.

    Any ideas?

    Thanks,

    Moneka

    Update:

    I actually went back to revisit my code. I made a few changes:

    1. I removed the interface
    2. I went back to the original web.config file

    My service is displaying xml correctly, and in the browser I am able to call my methods. However when I try to consume this in another application it cannot detect it at all. 

    Any ideas?

    Thanks,

    Moneka

    • Edited by Moneka Friday, May 30, 2014 8:58 PM
    Friday, May 30, 2014 7:08 PM
  • Hi,
    >>However when I try to consume this in another application it cannot detect it at all. 

    It should be a web reference and could be detected automatically, have you try to write the url address to the textbox directly and click go?


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, June 2, 2014 3:27 AM
    Moderator
  • Hi Fred,

    I have tried using it in the browser url - it works. However when I try using it in Linqpad or in the application with linq it doesn't recognize the method. 

    HTH,

    Moneka

    Monday, June 2, 2014 5:31 PM
  • >>However when I try using it in Linqpad or in the application with linq it doesn't recognize the method.

    No, you cannot do that with the WCF + EF application, we can use LINQ method because when we add a reference for the WCF Data Service, it will install the Microsoft.Data.Services.Client dll, these linq methods are under this namespace. And I read your original post, I am confused why you do not use the WCF Data Service which can completely do that you want:

    1.it gives us the capability of having access to all of the entities from the service.

    2. What I am trying to do is maintain that piece and also add in a service method (or 2) that I could expose through the service and consume in other applications.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Tuesday, June 3, 2014 8:21 AM
    Moderator