I have a Generic Service Interface:
[ServiceContract]
public interface IService<T> where T : Class1
{
[OperationContract]
void DoWork(T class1);
}
Then I have a Concrete Service that inherits from that:
public class Service : IService<Class1>
{
public void DoWork(Class1 class1)
{
}
}
Everything works fine until I add a webHttpEndpoint to expose a JSON WS:
<service name="Service">
<endpoint
address=""
binding="webHttpBinding"
behaviorConfiguration="webHttpBehavior"
contract="IService" />
</service>
<behavior name="webHttpBehavior">
<enableWebScript />
</behavior>
In fact, I receive this error:
The contract name 'IService' could not
be found in the list of contracts
implemented by the service 'Service'.
That's beacuse of the generic definition of the interface.
Any solution?
In my opinion (and based on what you said), the interface does not need to be generic. The caller just need to know that there is a DoWork operation.
So basically, change the concrete class to be generic instead of the interface.
public class Service<T> : IService where T : Class1
{
public void DoWork()
{
}
}
EDIT after clarifying the question: You need to provide the generic parameter in the config file as well:
contract="YourAssembly.IService`1[[YourAssembly.Class1, YourAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"
Here is a similar question: Inheriting from a generic contract in WCF
You must correctly write the type name of your contract into configuration. IService is not the name of IService<Class1>!!!
The configuration should look like:
<service name="Service">
<endpoint
address=""
binding="webHttpBinding"
behaviorConfiguration="webHttpBehavior"
contract="IService`1[Class1]" />
</service>
<behavior name="webHttpBehavior">
<enableWebScript />
</behavior>
Be aware that if your contract or service lives in any namespace, namespaces should be included in configuration.
Or in case of full names needed:
<service name="Namespace.Service, AssemblyName">
<endpoint
address=""
binding="webHttpBinding"
behaviorConfiguration="webHttpBehavior"
contract="Namespace.IService`1[[Namespace.Class1, AssemblyName]], AssemblyName" />
</service>
<behavior name="webHttpBehavior">
<enableWebScript />
</behavior>
Where is your Class1.....Instead of specifying any specific class make it a reference type using class
Try something this...
[ServiceContract]public interface IService<T> where T : class
{
[OperationContract]
void DoWork();
}
Related
I'm new to WCF and I've been hitting my head for the past week trying to get everything to work. When browsing the service.svc file I receive the message about the metadata not being enabled. There's hundreds of posts on this but I must be missing something. I think I followed the instructions correctly but I still can't find my error. Where am I going wrong? Any help is appreciated.
service.svc
<%# ServiceHost Service="BiteSizeLearningWS.TranscriptService" Debug="true" %>
web.config
<services>
<service name="BiteSizeLearningWS.iServiceInterface" behaviorConfiguration="TranscriptServiceBehavior">
<endpoint address="" binding="basicHttpBinding" contract="BiteSizeLearningWS.TranscriptService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="TranscriptServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
ServiceContract
namespace BiteSizeLearningWS
{
[ServiceContract (Name="TranscriptService")]
public interface iServiceInterface{...
Implementation
public class TranscriptService : iServiceInterface
Global.asax
namespace BiteSizeLearningWS
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add(new ServiceRoute("TranscriptService", new WebServiceHostFactory(), typeof(TranscriptService)));
}
I think you have your:
<service name="BiteSizeLearningWS.iServiceInterface"...
name attribute value and the
<endpoint address="" ... contract="BiteSizeLearningWS.TranscriptService" />
contract attribute value mixed up. Try this:
<service name="BiteSizeLearningWS.TranscriptService"...
and
<endpoint address="" ... contract="BiteSizeLearningWS.iServiceInterface" />
If that works, then what happened is that WCF used the automatic default configuration values for the service instead of the invalid configuration shown in the question. The metadata endpoint is not enabled by default which would be why you're seeing the "disabled" message.
I have a simple WCF service defined by the following ServiceContract:
[ServiceContract]
public interface IInventoryService
{
[OperationContract]
Item GetItemFromBarcode(string barcode);
[OperationContract]
string Test(string testString);
}
With Item defined like this:
[DataContract]
public class Item
{
[DataMember]
public virtual int Id { get; set; }
<Snip>
}
And the actual service implemented thusly:
public class InventoryService : IInventoryService
{
[WebGet(UriTemplate = "/Barcode/{barcode}/Item", ResponseFormat = WebMessageFormat.Json)]
public Item GetItemFromBarcode(string barcode)
{
var item = (from b in repository.Query<ItemBarcode>()
where b.BarcodeData == barcode
select b.Item).FirstOrDefault();
return item;
}
[WebGet(UriTemplate = "/Test/{testString}",ResponseFormat=WebMessageFormat.Xml)]
public string Test(string testString)
{
return testString;
}
}
With the following in the app.config for the program hosting the service:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="RESTFriendly">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="InventoryService">
<endpoint address="/Inventory" behaviorConfiguration="RESTFriendly" binding="webHttpBinding" contract="IInventoryService"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
Now that the code dump is out of the way, the issue: I can invoke the Test method just fine with curl or Fiddler, it returns a serialized string. However, invoking the method that returns an object returns nothing. Curl spits back curl: (56) Failure when receiving data from the peer and Fiddler responds ReadResponse() failed: The server did not return a response for this request.
From what I read, this should Just Work (tm). Is there something obvious I'm missing?
So, it seems you can't have DataMember of an interface type, like the IList<ItemBarcode>. There go my hopes of using my NHibernate model objects as DTOs.
We've tried to use a very very simple WCF service with a HTTp Get and we can't get it work.
We've followed those "guide" but it doesn't work
http://msdn.microsoft.com/en-us/library/bb412178.aspx
http://www.dotnetfunda.com/articles/article779-simple-5-steps-to-expose-wcf-services-using-rest-style-.aspx
When we call our service with the following url, we get a page not found error:
http://localhost:9999/Service1.svc/GetData/ABC
The base url (http://localhost:9999/Service1.svc) works fine and returns the wcf service information page correctly.
Those are the steps and code to reproduce our example.
In Visual Studio 2010, create a new "WCF Service Application" Project
Replace the IService interface with this code
[ServiceContract()]
public interface IService1
{
[OperationContract()]
[WebInvoke(Method = "GET",
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "GetData/{value}")]
string GetData(string value);
}
Replace the Service class with this code
public class Service1 : IService1
{
public string GetData(string value)
{
return string.Format("You entered: {0}", value);
}
}
The web.config look like this
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="Service1">
<endpoint address="" binding="webHttpBinding" contract="IService1" behaviorConfiguration="WebBehavior1">
</endpoint>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="WebBehavior1">
<webHttp helpEnabled="True"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
Press Run and try to call the Get method
If someone get this or something similar working, it would be very kind if you could reply information about the working example.
Thank you very much
I recreated your sample - works like a charm.
One point: do your service contract (public interface IService1) and service implementation (public class Service1 : IService1) exist inside a .NET namespace??
If so, you need to change your *.svc and your web.config to include:
<services>
<service name="Namespace.Service1">
<endpoint address="" binding="webHttpBinding"
contract="Namespace.IService1"
behaviorConfiguration="WebBehavior1">
</endpoint>
</service>
</services>
The <service name="..."> attribute and the <endpoint contract="..."> must include the .NET namespace for this to work.
[ServiceContract]
public interface ISecurities<T> : IPolicyProvider where T: EntityObject
{
[OperationContract(Name="GetAllSecurities")]
IEnumerable<T> GetSecurities();
[OperationContract]
IEnumerable<T> GetSecurities<T1>(List<T1> lstIdentifiers) where T1 : FI_CusipMaster;
[OperationContract]
T GetSecurity<T1>(T1 lstIdentifiers) where T1 : FI_CusipMaster;
}
//Host
///CADIS Contract
ServiceHost dmHost = new System.ServiceModel.ServiceHost(typeof(GlobalInvestors.FIPA.BLL.UDI.CADISSecurities));
Uri baseAddress = dmHost.BaseAddresses[0];
Uri policyAddress = new Uri(baseAddress.AbsoluteUri.Replace(baseAddress.AbsolutePath, ""));
dmHost.AddServiceEndpoint(
typeof(GlobalInvestors.FIPA.BLL.IPolicyProvider),
new System.ServiceModel.WebHttpBinding(),
policyAddress).Behaviors.Add(new System.ServiceModel.Description.WebHttpBehavior());
dmHost.Open();
//App.Config
<service behaviorConfiguration="UDIBehaviour" name="GlobalInvestors.FIPA.BLL.UDI.CADISSecurities">
<endpoint binding="basicHttpBinding" contract="GlobalInvestors.FIPA.BLL.UDI.ICADISSecurities" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:1667/CADIS" />
</baseAddresses>
</host>
</service>
<behavior name="UDIBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
[ServiceContract]
[ServiceKnownType(typeof(SecurityMasterAdapter))]
public interface ICADISSecurities :ISecurities<SecurityMasterAdapter>
{
}
I get "InvalidDataContractException Type 'System.Collections.Generic.List`1[T1]' cannot be exported as a schema type because it is an open generic type. You can only export a generic type if all its generic parameter types are actual types." if I host this contract.
I have read that it is good to avoid generics in ServiceContract. but is it possible to use T?
Your problem in this case is not T in ServiceContract but T1 used as DataContract. You can use T in service contract if you replace T with specific type during service contract implementation. For data contracts (operation parameters and return types) you can't use T at all. You always have to specify concrete type. Your service contract can be rewritten with usage of ServiceKnownTypeAttribute so that T1 is replaced with FI_CusipMaster and ServiceKnownType specifies all possible classes derived from FI_CusipMaster.
Edit: Another way is not to use ServiceKnownType and use KnownTypeAttribute which has to be defined on FI_CusipMaster type.
Best regards, Ladislav
As the error says, no you cannot use T. Service contracts need to be able to write out serialization information that deals with definitive types. It can't handle open generics in the exported functions
In your example T is a generic type. You cannot use a generic type in a ServiceContract unless it is used with a defined type parameter- as in class Foo : List<int> { }.
I have a WCF service that is hosted in IIS. I want to use my own IAuthorizationPolicy, and have it configured in the web.config file on the server. I have my auth policy:
namespace MyLib.WCF
{
public class CustomAuthorizationPolicy : IAuthorizationPolicy
{
public CustomAuthorizationPolicy()
{
this.Id = Guid.NewGuid().ToString();
}
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
throw new ApplicationException("Testing custom auth");
}
...
}
}
And in my web.config:
<service behaviorConfiguration="Behavior" name="MyService">
<endpoint address="" binding="wsHttpBinding" contract="IMyService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<serviceBehaviors>
<behavior name="Behavior">
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="MyLib.WCF.CustomAuthorizationPolicy, MyLib.WCF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</authorizationPolicies>
</serviceAuthorization>
</behavior>
</serviceBehaviors>
But my CustomAuthorizationPolicy.Evaluate() method never fires. What am I missing?
Well, the obvious (silly) question is: in your <service>, do you actually reference your behavior configuration??
I.e. do you have:
<system.serviceModel>
....
<service name="YourService" behaviorConfiguration="Behavior">
....
</service>
....
</system.serviceModel>
Just defining all your stuff is nice and well - but unless you've actually referenced it, it won't do you any good (been there, done that myself, too! :-) )
Second (almost as silly) question would be: what binding and security config do you use?? Have you even turned on security at all? If you have <security mode="None">, then your service authorization will obviously never be used, either (since no credentials are being passed to the service at all).
Marc