I used this MSDN example to construct my console host app:
http://msdn.microsoft.com/en-us/library/ms731758.aspx
It works I have a service running, while running I can add it as a Service Reference to my Silverlight class library ViewModel and I can see it running in a browser.
However when I run my Silverlight app I get the following error message:
Could not find default endpoint element that references contract
'ServiceLayer.IServiceLayer' in the ServiceModel client configuration
section. This might be because no configuration file was found for
your application, or because no endpoint element matching this
contract could be found in the client element.
This is my service code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Activation;
using Model;
namespace ServiceLayer
{
[ServiceContract(Namespace = "ServiceLayer")] //This has to match references or updating the service reference will not work.
public interface IServiceLayer
{
[OperationContract] //This is needed for each method.
string Compile(string cscode, string name, string type, int token);
[OperationContract] //This is needed for each method.
string LoginClick(string username, string password, bool createuser, int token);
[OperationContract]
bool IsLoggedIn(int token);
[OperationContract] //This is needed for each method.
object[] GetMessages(int token);
[OperationContract] //This is needed for each method.
int GetToken(int token);
[OperationContract] //This is needed for each method.
string[][] GetPlugins(int token);
[OperationContract] //This is needed for each method.
string Finalize(int token, string[] descriptions);
[OperationContract] //This is needed for each method.
object[][] Communicate(string methodName, int token, object[] args);
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ServiceLayer : IServiceLayer
{
public string Compile(string cscode, string name, string type, int token)
{
// Add your operation implementation here
ModelInterface MI = new ModelInterface();
return MI.Compile(cscode, name, type, token);
}
public String LoginClick(string username, string password, bool createuser, int token)
{
ModelInterface MI = new ModelInterface();
return MI.LoginClick(username, password, createuser, token);
}
public bool IsLoggedIn(int token)
{
ModelInterface MI = new ModelInterface();
return MI.IsLoggedIn(token);
}
public object[] GetMessages(int token)
{
ModelInterface MI = new ModelInterface();
return MI.GetMessages(token);
}
public int GetToken(int token)
{
ModelInterface MI = new ModelInterface();
return MI.GetToken(token);
}
public string[][] GetPlugins(int token)
{
ModelInterface MI = new ModelInterface();
return MI.GetPlugins(token);
}
public string Finalize(int token, string[] descriptions)
{
ModelInterface MI = new ModelInterface();
return MI.Finalize(token, descriptions);
}
public object[][] Communicate(string methodName, int token, object[] args)
{
ModelInterface MI = new ModelInterface();
return MI.Communicate(methodName, token, args);
}
// Add more operations here and mark them with [OperationContract]
}
}
This is the ServiceReferences.ClientConfig of the ViewModel:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IServiceLayer" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
<binding name="BasicHttpBinding_IServiceLayer1" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:3263/front" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IServiceLayer" contract="IServiceLayer"
name="BasicHttpBinding_IServiceLayer" />
<endpoint address="http://localhost:3263/front" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IServiceLayer1" contract="ServiceLayer.IServiceLayer"
name="BasicHttpBinding_IServiceLayer1" />
</client>
</system.serviceModel>
And this is the Web.Config file of the project with the website hosting the Silverlight app.
I post it because I tried this Could not find default endpoint element
guide - ie copying the servicemodel section from the VM config to the web.Config below also:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<pages controlRenderingCompatibilityVersion="4.0"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="OrgOS.Web.ServerCommunicationService.customBinding0">
<binaryMessageEncoding/>
<httpTransport/>
</binding>
<binding name="OrgOS.Web.ServiceLayer.customBinding0">
<binaryMessageEncoding/>
<httpTransport/>
</binding>
</customBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
<services>
<service name="OrgOS.Web.ServiceLayer">
<endpoint address="" binding="customBinding" bindingConfiguration="OrgOS.Web.ServiceLayer.customBinding0" contract="OrgOS.Web.ServiceLayer"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
My server I rented came without ASP.NET despite the fact I paid for it, support is on leave and I have deadlines coming up!
Trying to get WCF working is driving me mad - please help me...
Why is it so freaking hard to show a simple Silverlight project...
Ah nevermind; you have to post the config settings in both the View Silverlight project, the web project AND the ViewModel Silverlight project.
You must also delete all endpoints and bindings, but one to avoid getting things confused.
Also changed things to make sure namespace="namespace" fits the actual namespace.
... not that things work for that reason, oh noes all I get is invalid results.
FML right now.
Related
I have a problem with metadata (wsdl on service soap).
Locally everything works fine. and at the address https: // localhost / DataImportSoapService /? wsdl the wsdl is exposed.
Nothing is shown on the server. Return 404.
I state that I have other active services in WCF and that the other .svc are correctly exposed.
While this basicHttpBinding service with basic auth doesn't work.
So on the server I activated everything:
My web.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DatineoUser" value="zzzzzz" />
<add key="DatineoPass" value="xxxx" />
<add key="UrlServiceNewEra" value="https://xxxxx/common/importDataCarrier?satcode=datineo" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service behaviorConfiguration="MetadataBehavior" name="TA_service_library_BA.DataImportSoapService">
<endpoint address="datineoV1" binding="basicHttpBinding"
bindingConfiguration="wsHttpBinding_LargeBinding" name="EndpointAVeryBigSum_BasicAuthentication"
contract="TA_service_library_BA.IDataImportSoapService" />
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="https://localhost/DataImportSoapService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MetadataBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="TA_service_library_BA.ServiceAuthenticator, TA_service_library_BA"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="wsHttpBinding_LargeBinding" closeTimeout="00:05:00" openTimeout="00:05:00" receiveTimeout="00:15:00" sendTimeout="00:15:00" maxBufferSize="15728640" maxBufferPoolSize="15728640" maxReceivedMessageSize="15728640">
<readerQuotas maxDepth="2000000" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
</configuration>
My classes:
namespace TA_service_library_BA
{
public class ServiceAuthenticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
throw new SecurityTokenException("Username and password required");
if (!(userName == ConfigurationManager.AppSettings["DatineoUser"] && password == ConfigurationManager.AppSettings["DatineoPass"]))
throw new FaultException(string.Format("Wrong username ({0}) or password ", userName));
}
}
}
namespace TA_service_library_BA
{
// NOTA: è possibile utilizzare il comando "Rinomina" del menu "Refactoring" per modificare il nome di interfaccia "IDataImportService" nel codice e nel file di configurazione contemporaneamente.
[ServiceContract(Namespace = "http://sen.company.com")]
[XmlSerializerFormat]
public interface IDataImportSoapService
{
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare)]
PushResponse PushDataArray(PushData pushDataArray);
//++++++++++++++++++++++++++++++++++++++++++++++
}
}
namespace TA_service_library_BA
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
public class DataImportSoapService : IDataImportSoapService
{
public PushResponse PushDataArray(PushData pushDataArray)
{
PushResponse responsePush = new PushResponse();
try
{
string authkey = ConfigurationManager.AppSettings["DatineoUser"] + ":" + ConfigurationManager.AppSettings["DatineoPass"];
string encAuthkey = CommFun.Base64Encode(authkey);
WebRequest request = WebRequest.Create(ConfigurationManager.AppSettings["UrlServiceNewEra"]);
request.ContentType = "application/json";
request.Method = "POST";
request.Headers.Add("Authorization", "Basic " + encAuthkey);
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
string json = new JavaScriptSerializer().Serialize(pushDataArray);
streamWriter.Write(json);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
if (response.StatusCode.Equals(HttpStatusCode.OK) || response.StatusCode.Equals(HttpStatusCode.NoContent))
{
//istanzio la risposta contenitore
responsePush.success = true;
responsePush.message = responseString;
}
else
{
//istanzio la risposta contenitore
responsePush.success = false;
responsePush.message = responseString;
}
}
catch (Exception ex)
{
//istanzio la risposta contenitore
responsePush.success = false;
responsePush.message = ex.Message;
}
return responsePush;
}
}
}
Why do some projects expose at least the .svc while this last service gives me 404 to the .svc file?
Beyond this then I don't understand what the hell is wrong with the configuration ... with IIS express everything goes .. on the server no.
Thanks for your help. I've been banging my head for a week and a half. I have tried the impossible. Tnx
You can check the following conditions:
Whether the permission of the managed directory is granted.
Whether the.NET version matches.
Is there a valid certificate on the site.
Try to put the image in the same path and find it.
I created a wcf application. I didn't change anything. Used the Service1.GetData(int). It works fine. I can hit the wsdl in a browser and everything. Then I created a custom service host factory that simply returns a new service host and the service never comes up. I can no longer get to the wsdl in a browser. I tried adding a Custom ServiceHost so I could do a little debugging and it appears that there are no endpoints being found (even when explicitly calling AddDefaultEndpoints(). This is true even when I explicitly add the endpoint to the web.config.
Does anyone have any ideas as to what the issue could be?
If anyone cares to take a look I put the code on github: https://github.com/devlife/Sandbox/tree/master/WcfService1
Why are you using ServiceHostFactory?
are you going to use AppFabric/IIS? or self hosted services?
I think you need to add a MEX endpoint.
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
Here is how I have defined a CustomHost in a project I am working on,
<%# ServiceHost Language="C#" Debug="true" Service="Servicename.Servicename" CodeBehind="Service1.svc.cs" Factory="WcfService1.CustomServiceHostFactory"%>
And this,
public class CustomServiceHostFactory : ServiceHostFactory
{
public CustomServiceHostFactory()
{
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new CustomServiceHost(serviceType, baseAddresses);
}
}
public class CustomServiceHost : ServiceHost
{
public CustomServiceHost()
{
}
public CustomServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
}
protected override void OnOpening()
{
base.OnOpening();
}
protected override void OnClosing()
{
base.OnClosing();
}
protected override void ApplyConfiguration()
{
base.ApplyConfiguration();
}
}
Note that the CustomServiceHost looks bare, but that is because my solution has a lot of logging and configuration in this CustomServiceHost that I removed and is not appropriate.
The other difference I can see also is that my CustomServiceHost does not add the endpoint. The endpoint is defined in the config file like this,
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Servicename.Servicename" behaviorConfiguration="ServiceBehavior">
<endpoint address="http://*******.svc" binding="wsHttpBinding" contract="Namespace.IContract" bindingConfiguration="BindingConfig">
</endpoint>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="BindingConfig" maxReceivedMessageSize="9291456">
<security mode="None">
</security>
<readerQuotas maxArrayLength="6291456" />
</binding>
</wsHttpBinding>
</bindings>
I have a requirement of creating a webservice where the client and the service will talk in Simple Soap (that request and response will be soap), I tried all to find a sample example on net where this thing is already done or some code sample so that I can get started but I think I am bad in searching google, that is why can't find any one so far, Some one suggested to use WCF so get an article
http://csharping.com/wcf/building-a-soap-response-envelope-manually-with-the-message-class/
But again my problem is not solved, I tried to create an application with this sample (with so many issues :( )
Created a console application and the Program.cs is
using System;
using System.IO;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Runtime.Serialization;
namespace ServiceConsole
{
public class Program
{
static void Main(string[] args)
{
using (ServiceHost serviceHost = new ServiceHost(typeof(ServiceClient), new Uri("http://localhost:2000/")))
{
ServiceEndpoint serviceEndpoint = new ServiceEndpoint(
ContractDescription.GetContract(typeof(IService)));
ServiceEndpoint metadataEndpoint = new ServiceEndpoint(
ContractDescription.GetContract(typeof(IMetadataExchange)));
ServiceMetadataBehavior metadataBehavior = serviceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (metadataBehavior == null)
{
metadataBehavior = new ServiceMetadataBehavior();
metadataBehavior.HttpGetEnabled = true;
serviceHost.Description.Behaviors.Add(metadataBehavior);
}
serviceHost.AddServiceEndpoint(typeof(IService), new BasicHttpBinding(), "http://localhost:2000/");
serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "http://localhost:2000/WCFService/mex");
serviceHost.Open();
string requestData = "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Header><h:HeaderItem xmlns:h=\"http://tempuri.org/\">a header item</h:HeaderItem><ActivityId CorrelationId=\"090c553b-bfcc-4e4f-94cd-1b4333fe82a9\" xmlns=\"http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics\">377a454b-b543-4c6f-b4ac-3981029b60e6</ActivityId></s:Header><s:Body><string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">a body item</string></s:Body></s:Envelope>";
byte[] requestDataBytes = Encoding.UTF8.GetBytes(requestData);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost/WCFService/");
request.Method = "POST";
request.ContentType = "text/xml; charset=utf-8";
request.Headers.Add("SOAPAction", "http://tempuri.org/IWebService/GetMessage");
request.ContentLength = requestDataBytes.Length;
StreamWriter streamWriter = new StreamWriter(request.GetRequestStream());
streamWriter.Write(requestData);
streamWriter.Flush();
streamWriter.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader streamReader = new StreamReader(response.GetResponseStream());
string responseBody = streamReader.ReadToEnd();
Console.WriteLine("Service returned the following response...");
Console.WriteLine("");
Console.WriteLine(responseBody);
Console.ReadKey();
serviceHost.Close();
}
}
}
}
the app.config which I generated using svcutil.exe is like this
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:2000/WebService/Service.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService"
contract="IService" name="BasicHttpBinding_IService" />
</client>
</system.serviceModel>
</configuration>
My webservioce is like (it is a WCF website in which the port is provided by me and is 2000
Service contract is
[ServiceContract]
public interface IService
{
[OperationContract]
Message GetMessage(Message s);
}
[ServiceBehavior]
public class Service : IService
{
public Message GetMessage(Message message)
{
string body = message.GetBody<string>();
return Message.CreateMessage(MessageVersion.Soap11, "http://tempuri.org/IWebService/GetMessageResponse", "body is " + body);
}
}
and the web.config is
<system.serviceModel>
<services>
<service behaviorConfiguration="ServiceBehavior" name="Service">
<endpoint address="http://localhost:2000/WebService/Service.svc" binding="basicHttpBinding" bindingConfiguration=""
contract="IService" >
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<timeouts closeTimeout="00:01:10" />
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" policyVersion="Policy15" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
My issue is 405 webmethod not body can anyone please tell me what is an issue in this, I am new to WCF before this created a sample and this is my second application
You do not need to create the SOAP message manually, just use basic http binding and that will rturn SOAP.
When you have a WCF service, the whole point is that you can define e.g. parameters like strings, int and so forth - and you don't have to mess with loads of XML and SOAP headers and bodies.
So basically, your service contract should be something like:
[ServiceContract]
public interface IService
{
[OperationContract]
int DoSomeMathAddTowNumbers(int num1, int num2);
}
and your service implementation would then just implement that method, add the two numbers, and return the result:
public class Service : IService
{
int DoSomeMathAddTowNumbers(int num1, int num2)
{
return num1 + num2;
}
}
No mess with Message or XML manipulation or anything.
A client that wants to call your service would create a WCF client-side proxy using svcutil or the Visual Studio Add Service Reference method, and it would get a proxy class that has the same methods as the service it connects to - and you would call them, using the straight, easy parameters - something like:
ServiceClient client = new ServiceClient();
int result = client.DoSomeMathAddTwoNumbers(42, 100);
So basically, I think you need to get back to the drawing board and read up on the WCF basics again - it should not be that difficult, really! (that's the whole point - it should make services easy ...)
Check out the Beginner's Guide at the WCF Developer Center at MSDN - it contains lots of really good videos, screencasts, articles on how to get started with WCF.-
You might also want to check out the DotNet Rocks TV episode #135: Keith Elder Demystifies WCF
how to use [PrincipalPermission(SecurityAction.Demand, Role = "Administrators")] attribute on a class?
I am looking for some way to restrict the access on my object
i.e
if some object is being accessed in a service method and if the user has rights for accessing the service method but does not have rights accessing the object an exception should be thrown
PrincipalPermission attribute can adorn method or class. Therefore it is possible to restrict access to an instance of an object. Several things need to be done:
Configure selected service and client binding to use security. Specify Windows as client credential type.
Configure service to use Windows groups for authorization.
Adorn class that will contain confidential information with PrincipalPermission attribute.
If singleton instance needs to be passed to ServiceHost constructor, do following:
Create service singleton instance. Thread.CurrentPrincipal must have permissions necessary to access the confidential object.
Create ServiceHost instance by passing service singleton instance. Property InstanceContextMode of ServiceBehavior attribute must be set to InstanceContextMode.Single.
Otherwise:
Create ServiceHost instance by passing the service type.
Optionally, adorn the service method with FaultContract attribute and throw FaultException from it in order to avoid faulting the client channel.
Here is an example:
Service configuration file:
<system.serviceModel>
<services>
<service name="Server.Service" behaviorConfiguration="Authorization">
<endpoint address=""
binding="netTcpBinding" bindingConfiguration="TCP"
contract="Common.IService" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:13031/Service"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="TCP" openTimeout="00:30:00" closeTimeout="00:00:10" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
<security mode="Message">
<message clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Authorization">
<serviceAuthorization principalPermissionMode="UseWindowsGroups" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Client configuration file:
<system.serviceModel>
<client>
<endpoint name="NetTcpBinding_IService"
address="net.tcp://localhost:13031/Service"
binding="netTcpBinding" bindingConfiguration="TCP"
contract="Common.IService" />
</client>
<bindings>
<netTcpBinding>
<binding name="TCP" openTimeout="00:30:00" closeTimeout="00:00:10" sendTimeout="00:30:00" receiveTimeout="00:30:00" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
<security mode="Message">
<message clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
Confidential information class:
[PrincipalPermission(SecurityAction.Demand, Role = "Administrators" ) ]
public class ContactInfo
{
public string FirstName { get; set; }
public string LastName { get; set; }
public ContactInfo()
{
FirstName = "John";
LastName = "Doe";
}
public override string ToString()
{
return string.Format( "{0} {1}", FirstName, LastName );
}
}
Service contract and its implementation:
[ServiceContract]
public interface IService
{
[OperationContract]
[FaultContract( typeof( string ) )]
string GetName( int id );
}
[ServiceBehavior]
// Use following if singleton instance needs to be passed to `ServiceHost` constructor
//[ServiceBehavior( InstanceContextMode = InstanceContextMode.Single )]
public class Service : IService
{
private Dictionary<int, ContactInfo> Contacts { get; set; }
public Service()
{
Contacts = new Dictionary<int, ContactInfo>();
IPrincipal originalPrincipal = Thread.CurrentPrincipal;
try
{
Thread.CurrentPrincipal = new WindowsPrincipal( WindowsIdentity.GetCurrent() );
Contacts.Add( 1, new ContactInfo() );
}
finally
{
Thread.CurrentPrincipal = originalPrincipal;
}
}
public string GetName( int id )
{
if ( Contacts.Count < id )
return null;
try
{
return Contacts[ id ].ToString();
}
catch ( Exception ex )
{
throw new FaultException<string>( ex.Message );
}
}
}
If you are familiar with .NET permission coding (either imperative or declarative), the pattern is exactly the same. In the declarative form, the PrincipalPermissionAttribute is applied to the method in the class that implements the service’s contract:
[PrincipalPermission(SecurityAction.Demand, Role = "Updaters")]
public bool Update()
{
return true;
}
In this example, the current principal is checked to see whether it belongs to a role called Updaters. In the actual implementation of the attribute, the IsInRole method on the principal is called.
For imperative determination of the PrincipalPermissionAttribute, an instance of the PrincipalPermission class is created. The constructor for PrincipalPermission takes the username and role as a parameter. When instantiated, the Demand method can be called to determine whether the current principal has the necessary permissions. The following code provides an example:
PrincipalPermission p = new PrincipalPermission(null, "Updaters");
p.Demand();
the configuration should look like this:
<behaviors>
<serviceBehaviors>
<behavior>
...
<serviceAuthorization principalPermissionMode="UseWindowsGroups" />
</behavior>
</serviceBehaviors>
</behaviors>
for a working sample please look at: Authorizing Access to Service Operations
Sorry for asking a question about something I don't know much about, but I've been pulling my hair out trying to get this working.
So, I have a WCF service that is hosted on IIS and seems to be working insomuch that I can "see" it on the network by going to http://servername/MyService.svc in a browser.
That .svc looks like:
<% #ServiceHost Service="Foo.Bar" %>
The relevant code looks like:
[ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06Services/Notification/03")]
public interface IBar
{
[OperationContract(Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", ReplyAction = "*")]
[XmlSerializerFormat(Style = OperationFormatStyle.Document)]
void Notify(string eventXml, string tfsIdentityXml);
}
and:
public class Bar : IBar
{
public void Notify(string eventXml, string tfsIdentityXml)
{
// Just some test output to see if it worked
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "tfs.txt");
File.WriteAllText(path, tfsIdentityXml + eventXml);
}
}
That's all been built and the ensuing .dll put into the bin dir in the site root in IIS.
I now want to subscribe via bissubscribe.exe (or a similar method) to TFS check-in events. I tried doing something like:
bissubscribe /eventType CheckinEvent
/address http://servername/MyService.svc
/deliveryType Soap
/server mytfsserver
But nothing; it doesn't even look like there was log activity. So keeping in mind I know nothing about WCF, what am I doing wrong? I imagine the address param is one thing; am I not supposed to point it to the .svc?
I have created a blog post how you can use WCF in combination with the Event Services of TFS: http://www.ewaldhofman.nl/post/2010/08/02/How-to-use-WCF-to-subscribe-to-the-TFS-2010-Event-Service-rolling-up-hours.aspx
TFS 2010 and WCF 4.0 configurations are described below...
Method signature:
public void Notify(string eventXml) /* No SubscriptionInfo! */
Web config:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="Microsoft.TeamFoundation, Version=10.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
</assemblies>
</compilation>
</system.web>
<system.serviceModel>
<services>
<service behaviorConfiguration="NotificationServiceBehavior" name="TF.CheckinListener.CheckinListener">
<endpoint address="Notify" binding="wsHttpBinding" bindingConfiguration="noSecurity" contract="TF.CheckinListener.ICheckinListener" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="NotificationServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
</binding>
<wsHttpBinding>
<binding name="noSecurity" maxBufferPoolSize="20000000" maxReceivedMessageSize="200000000">
<readerQuotas maxStringContentLength="200000000" maxArrayLength="200000000" />
<security mode="None" />
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Subscription address for bissubscribe:
http://MachineName/VirtualDirectoryName/Service.svc/Notify
One point that jumps out is the fact you have a method that doesn't return anything except void. Those should be marked as "one-way" method in WCF:
[ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06Services/Notification/03")]
public interface IBar
{
[OperationContract(Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", ReplyAction = "*", IsOneWay=true)]
[XmlSerializerFormat(Style = OperationFormatStyle.Document)]
void Notify(string eventXml, string tfsIdentityXml);
}
Add the "IsOneWay=true" to your [OperationContract] attribute.
Other than that, there's nothing obviously wrong in your code, but to really tell, we'd need a lot more config info to really tell. Try the IsOneWay=true first and see if that solves your issue.
How is your service configured? In particular, is it configured to use basicHttpBinding?
Try creating a client to call your service to make sure it can be called.
Then, see if there's an example service from the TFS SDK - see if you can get the example to work.
I was able to complete this connection with the following:
[ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
public interface ITeamSystemObserver : IObservable
{
[OperationContract( Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", ReplyAction = "*" )]
[XmlSerializerFormat(Style=OperationFormatStyle.Document)]
void Notify(string eventXml, string tfsIdentityXml, SubscriptionInfo SubscriptionInfo);
}
Note you are missing the SubscriptionInfo parameter. Here is my web.config:
<basicHttpBinding>
<binding name="TfsEventServiceBasic">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" />
</security>
</binding>
</basicHttpBinding>