I have a WCF service with basicHttpBinding. This service is loading data and its related objects from database via ADO.net Entity framework. I have disabled Proxy creation:
using (var db = new ComputerDealsDb())
{
db.Configuration.ProxyCreationEnabled = false;
db.Configuration.LazyLoadingEnabled = false;
DealItem dealItem = (from d in db.DealItems.Include("DealReviews")
where d.DealItemId == itemId
select d).FirstOrDefault<DealItem>();
return dealItem;
}
The service is referred in a web project and giving Communication exception. Can anyone assist me in this regard. Thanks
Related
I have a WCF RIA Service with methods that return IQueryable<>. I want to access this methods using ClannelFactory from a
console application. I have an interface on the client that matches the the methods in my RIA Service. When I run the server and
the client applications I can see that the server method is called and an IQuery<> object is returned. The problem is that on the
client I can't get the data sent by the server. I can see that data actually comes by using Fiddler, but I think that the data can't be
deserialized to IQueryable.
For me the type of the data received doesn't matter. I'll be happy with just an array. But because the method in the
service returns IQueryable my OperationContract method on the client has the same type.
So the question is how to get the data from the server, without changing the return type (IQueryable) on the server side?
Server side:
public IQueryable<Customers> GetCustomers()
{
List<Customers> customersList = new List<Customers>();
customersList.Add(new Customer())
...
return customersList.AsQueryable();
}
Client side:
[ServiceContract]
public interface CustoemrsService
{
[OperationContract]
IQueryable<Customers> GetCustomers();
}
And the ChannelFactory code:
var endpointAddress = new EndpointAddress(_endpointAddress);
var channelFactory = new ChannelFactory<VfxSystemDomainServiceSoap>(new BasicHttpBinding());
var channel = channelFactory.CreateChannel(endpointAddress);
IQueryable<Customers> customersCollection = channel.GetVfxfopenQuery();
I decided to open a new question about this matter, maybe expanding this question, not having found a precise answer about the issue anywhere on the Internet.
I want to use protobuf-net to serialize/deserialize messages exchanged between my WCF client and service. The service is self-hosted in a Windows Service. Both client and service are configured programmatically, using a custom binding very similar to wsHttpBinding. Service reference code is generated using "Add Service Reference" option in Visual Studio. The ORM used on the WCF service is EntityFramework 4 and it's code is generated using EF 4.x POCO Generator. More info about my service configuration can be found in a question I started here (that's where I described that my current serializer is DataContractSerialzizer).
I have only tested protobuf-net with one service operation which returns a list of custom DTOs.
Here is the operation (be advised that I just did a copy-paste of my code to here, there might be some fields named in my domestic language, not English):
public static List<OsobaView> GetListOsobas()
{
Database DB = new Database(); // EF object context
var retValue = DB.Baza.Osoba
.Select(x => new OsobaView
{
ID = x.ID,
Prezime = x.Prezime,
Ime = x.Ime,
Adresa = x.Adresa,
DatumRodjenja = x.DatumRodjenja,
JMBG = x.JMBG
});
return retValue.ToList();
}
Here is the definition of OsobaView class:
[ProtoContract]
public class OsobaView
{
[ProtoMember(1)]
public int ID;
[ProtoMember(2)]
public string Prezime;
[ProtoMember(3)]
public string Ime;
[ProtoMember(4)]
public string Adresa;
[ProtoMember(5)]
public DateTime DatumRodjenja;
[ProtoMember(6)]
public string JMBG;
}
As I am using "Add Service Reference" to generate the reference code, I had to use one of the two work-arounds in order to have my client recognize ProtoContracts and members:
using a shared assembly for DTOs (which is not an ideal solution in my case except for custom DTOs, due to the fact that I pass EF-generated POCOs to the client)
using ProtoPartialMember approach
I used both of them and I used both v1 and v2 of protobuf-net, all solutions yielded similar results which led me to believe my client is not deserializing at all. Read on.
Let's consider cases where I used the ProtoPartialMember approach. At first I used v2. I love the way ProtoOperationBehavior can be used. Here is the service operation to be invoked:
[ProtoBuf.ServiceModel.ProtoBehavior]
public List<OsobaView> GetListOsobas()
{
return OsobaQueries.GetListOsobas();
}
Here is how I replaced DataContractSerializerOperationBehavior with ProtoOperationBehavior for the needed service operation on client side:
OperationDescription op = Service.Proxy.Endpoint.Contract.Operations.Find("GetListOsobas");
if (op != null)
{
DataContractSerializerOperationBehavior dcsBehavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcsBehavior != null)
op.Behaviors.Remove(dcsBehavior);
op.Behaviors.Add(new ProtoBuf.ServiceModel.ProtoOperationBehavior(op));
}
And of course, here is the above mentioned work-around implementation for DTO:
[ProtoPartialMember(1, "ID")]
[ProtoPartialMember(2, "Prezime")]
[ProtoPartialMember(3, "Ime")]
[ProtoPartialMember(4, "Adresa")]
[ProtoPartialMember(5, "DatumRodjenja")]
[ProtoPartialMember(6, "JMBG")]
[ProtoContract]
public partial class OsobaView
{
}
Now when I call this service operation from my client, I get null. But Fiddler disagrees. It clearly says, in response header:
Content-Length: 1301963
Content-Type: application/soap+xml; charset=utf-8
...and in the message body:
<s:Body>
<GetListOsobasResponse xmlns="http://tempuri.org/">
<proto>CkMIpHES .../* REALLY LONG RESPONSE */... IyMDAxOA==</proto>
</GetListOsobasResponse>
</s:Body>
Then I thought, let's try with v1. On the service side, I haven't changed much. I just removed the reference to v2 .DLL and replaced it with a reference to v1 .DLL. On the client side, I had to remove the code to add ProtoOperationBehavior to my service operation behaviors and added the following line instead:
Service.Proxy.Endpoint.Behaviors
.Add(new ProtoBuf.ServiceModel.ProtoEndpointBehavior());
I fired it up, invoked the operation, and this time the result is not null. This time it is a list of blank fields. Again, Fiddler couldn't agree because it again said the same what it said before. The same content length and the same message body.
What's going on here?
P.S. If it's worth anything, here is the WCF configuration:
CustomBinding customBinding = new CustomBinding();
customBinding.CloseTimeout = TimeSpan.FromMinutes(10);
customBinding.OpenTimeout = TimeSpan.FromMinutes(10);
customBinding.ReceiveTimeout = TimeSpan.FromMinutes(10);
customBinding.SendTimeout = TimeSpan.FromMinutes(10);
HttpsTransportBindingElement httpsBindingElement = new HttpsTransportBindingElement();
httpsBindingElement.AllowCookies = false;
httpsBindingElement.BypassProxyOnLocal = false;
httpsBindingElement.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
httpsBindingElement.MaxBufferPoolSize = 20480000;
httpsBindingElement.MaxBufferSize = 20480000;
httpsBindingElement.MaxReceivedMessageSize = 20480000;
httpsBindingElement.RequireClientCertificate = true;
httpsBindingElement.UseDefaultWebProxy = true;
TransportSecurityBindingElement transportSecurityElement = new TransportSecurityBindingElement();
transportSecurityElement.EndpointSupportingTokenParameters.SignedEncrypted.Add(new UserNameSecurityTokenParameters());
transportSecurityElement.EndpointSupportingTokenParameters.SetKeyDerivation(false);
TransactionFlowBindingElement transactionFlowElement = new TransactionFlowBindingElement();
TextMessageEncodingBindingElement textMessageEncoding = new TextMessageEncodingBindingElement();
textMessageEncoding.MaxReadPoolSize = 20480000;
textMessageEncoding.MaxWritePoolSize = 20480000;
textMessageEncoding.ReaderQuotas = XmlDictionaryReaderQuotas.Max;
ReliableSessionBindingElement reliableSessionElement = new ReliableSessionBindingElement();
reliableSessionElement.ReliableMessagingVersion = ReliableMessagingVersion.WSReliableMessagingFebruary2005;
customBinding.Elements.Add(transportSecurityElement);
customBinding.Elements.Add(transactionFlowElement);
customBinding.Elements.Add(textMessageEncoding);
customBinding.Elements.Add(reliableSessionElement);
customBinding.Elements.Add(httpsBindingElement);
EndpointAddress endpoint = new EndpointAddress(new Uri(ServiceAddress));
Service.Proxy = new BazaService.BazaClient(customBinding, endpoint);
Service.Proxy.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, CertificateSubject);
CustomBehavior behavior = Service.Proxy.Endpoint.Behaviors.Find<CustomBehavior>();
if (behavior == null)
{
Service.Proxy.Endpoint.Behaviors.Add(new CustomBehavior()); // message inspector
}
Service.Proxy.Endpoint.Contract.Behaviors.Add(new CyclicReferencesAwareContractBehavior(true));
Service.Proxy.Endpoint.Behaviors.Add(new ProtoBuf.ServiceModel.ProtoEndpointBehavior());
/* code used for protobuf-net v2
OperationDescription op = Service.Proxy.Endpoint.Contract.Operations.Find("GetListOsobas");
if (op != null)
{
DataContractSerializerOperationBehavior dcsBehavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcsBehavior != null)
op.Behaviors.Remove(dcsBehavior);
op.Behaviors.Add(new ProtoBuf.ServiceModel.ProtoOperationBehavior(op));
} */
Service.Proxy.ClientCredentials.UserName.UserName = LogOn.UserName;
Service.Proxy.ClientCredentials.UserName.Password = LogOn.Password;
Service.Proxy.Open();
EDIT
To provide even more information, I have read what's written there but it didn't help. I have deleted the service reference generated by Visual Studio and created my own, sharing the whole service contract, but nothing has changed.
After concentrating a bit better, I decided to restart the solution from scratch. I created one class library for the EDMX with it's POCOs, one for ServiceContract and DataContracts and one for the actual WCF service implementation. Then I shared those two libraries containing ServiceContract and DataContracts, and POCOs with the WCF client and tried again, which yielded the same results as before. After trying some other operations which didn't use protobuf-net for serialization, turned out they behaved the same as the first one, resulting in empty fields (!).
The thing was that, I screwed my WCF client's .datasource files while refactoring after I decided to use the assembly sharing technique. So this was a typical PEBKAC, it of course works fine when done properly. Great work with protobuf-net, Marc Gravell!
Is there a shortcut for creating the most basic WCF Binding based on the address of a given Endpoint?
Endpoint: net.tcp://localhost:7879/Service.svc
Instead of a big block of if statements...
Binding binding = null;
if (endpoint.StartsWith("net.tcp"))
{
binding = new NetTcpBinding();
}
else if (endpoint.StartWith("http"))
{
binding = new WsHttpBinding();
}
.
.
.
Is there a shortcut in the Framework library that will do this for me that I just can't find or can I not find it because it doesn't publicly exist?
WCF in .NET 4 does that automatically for you - the feature is called default endpoints.
Read about all of WCF 4's new features here: A Developer's Introduction to WCF 4
Default endpoints is about the second or so paragraph into the article.
While WCF 4 supports default service endpoints, it does not support default client endpoints. Unfortunately the methods used by the framework to create default bindings are internal, but the logic behind it is simple, so I have reimplemented it to use on the client side (skipping original caching and tracing logic):
private static Binding GetBinding(string scheme)
{
// replace with ConfigurationManager if not running in ASP.NET
var configuration = WebConfigurationManager.OpenWebConfiguration(null);
var sectionGroup = ServiceModelSectionGroup.GetSectionGroup(configuration);
Debug.Assert(sectionGroup != null, "system.serviceModel configuration section is missing.");
var mapping = sectionGroup.ProtocolMapping.ProtocolMappingCollection
.OfType<ProtocolMappingElement>()
.SingleOrDefault(e => e.Scheme == scheme);
if (mapping == null)
throw new NotSupportedException(string.Format("The URI scheme {0} is not supported.", scheme));
var bindingElement = sectionGroup.Bindings.BindingCollections.Single(e => e.BindingName == mapping.Binding);
var binding = (Binding) Activator.CreateInstance(bindingElement.BindingType);
var bindingConfiguration = bindingElement.ConfiguredBindings.SingleOrDefault(e => e.Name == mapping.BindingConfiguration);
if (bindingConfiguration != null)
bindingConfiguration.ApplyConfiguration(binding);
return binding;
}
Without any configuration this code is equivalent to the code in the question, but you can select and configure your bindings inside the system.serviceModel/protocolMapping section.
After looking at the issue deeper I don't really need to read the configuration in manually. Instead I need to send the binding information along with the address and contract.
http://www.codeproject.com/KB/WCF/WCFDiscovery.aspx?display=PrintAll
I have built a simple component that serializes the binding information.
http://nardax.codeplex.com/
I have a client-server application, which intercommunicate via WCF. They also both use Castle Windsor for resolving dependencies.
My goal, is to completely avoid having to explicitly register server, or client WCF endpoints.
I have achieved the server-side by 'convention' using the following code
// registers all services which implement exactly 1 [ServiceContract]
_windsorContainer.Register(
AllTypes.FromThisAssembly().IncludeNonPublicTypes().Where(
t => 1 == (from i in t.GetInterfaces() where i.IsDefined(typeof(ServiceContractAttribute), true) select i).Count())
.Configure(c => c.LifeStyle.PerWcfSession()
.ActAs(new DefaultServiceModel().AddEndpoints(
WcfEndpoint.BoundTo(new NetTcpBinding())
.At("net.tcp://" + LocalAddress.ToString() + ":7601/" + c.ServiceType.Name),
WcfEndpoint.FromEndpoint(new UdpDiscoveryEndpoint())
))
).WithService.Select(
(Type type, Type[] baseTypes) => from i in type.GetInterfaces() where i.IsDefined(typeof(ServiceContractAttribute), true) select i
)
);
This code will find all classes in the current assembly, and any which implement a service-contract interface (identified by the ServiceContract attribute) will be registered (with UDP discovery) at the address "net.tcp://localhost:7601/[service-contract-interface-name]".
Now, I just want the client-side of the equation.
Typically, to use castle to generate client-proxies for WCF contracts, the following code will work:
var model = new DefaultClientModel
{
Endpoint = WcfEndpoint.ForContract<IServiceContract>().BoundTo(new NetTcpBinding()).Discover(typeof(IServiceContract))
};
container.Register(
Component.For<ChannelReconnectPolicy>(),
Castle.Facilities.WcfIntegration.WcfClient.ForChannels(model),
);
What I want, is for Castle to do this kind of registration for all 'service-contract' interfaces in a given assembly - however the AllTypes helper seems to return only classes, not interfaces (which I guess makes it an 'AllClasses', not 'AllTypes'!)... Can Castle do this, and what is the syntax? Krzysztof? (help!)
Thanks!
Apologies for such a late reply - a developer's life is never a quiet one!
I dug out the code, and its not as 'succinct' as I would have liked, perhaps someone can look at integrating something like this in to Castle... but here goes...
// these are all the namespaces that will be scanned for WCF service contracts
string[] remoteServiceNamespaces
= new string[] { "MyContracts.Services", "Interlinq" };
// everything from here on is in the Castle DLLs (all the types)
List<IRegistration> clientContractRegistrations = new List<IRegistration>();
foreach (
var interfaceContract in
(from s in remoteServiceNamespaces
select (from i in Assembly.LoadWithPartialName(s).GetTypes()
where i.IsInterface
&&
i.IsDefined(typeof(ServiceContractAttribute), false)
select i)).SelectMany( x => x )
)
{
ServiceContractAttribute attr
= Attribute.GetCustomAttribute(
interfaceContract,
typeof(ServiceContractAttribute))
as ServiceContractAttribute;
if (null != attr)
{
WcfClientModelBase model = null;
// here we handle the case of the service being duplex...
if (null != attr.CallbackContract)
{
model = new DuplexClientModel
{
// All the automatically registered services will use NetTcp,
// and will discover their addresses (you could use binding
// inference aswell if you liked)
// here I have a method called 'CreateNetTcpBinding' which
// creates my custom binding that ALL my services use.
Endpoint =
WcfEndpoint.ForContract(interfaceContract)
.BoundTo(CreateNetTcpBinding())
.Discover(interfaceContract)
.PreferEndpoint(list => list[0])
}.Callback(_windsor.Resolve(attr.CallbackContract));
}
else
{
model = new DefaultClientModel
{
Endpoint = WcfEndpoint.ForContract(interfaceContract)
.BoundTo(new NetTcpBinding())
.Discover(interfaceContract)
.PreferEndpoint(list => list[0])
};
}
clientContractRegistrations.Add(WcfClient.ForChannels(model));
}
}
// now that we've built our registration list, let's actually register
// them all with Windsor
_windsor.Register(
clientContractRegistrations.ToArray()
);
So I'm experiencing a strange error. I have a WP7 application that has a service reference to a WCF service I wrote. The WCF has an entity model for the database.
Basically what I want to happen, is when a user logs in on the phone, the matching SystemUser entry is returned from the WCF service. SystemUser is a table in the db.
On the WCF service side I have the following:
public SystemUser UserLogin(string emailAddress, string userPassword)
{
Regex emailRegex = new Regex(#"^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
if (emailRegex.IsMatch(emailAddress) && !string.IsNullOrEmpty(userPassword))
{
using (var context = new DBEntities())
{
var users = context.SystemUsers.Where(su => su.EmailAddress.ToLower().Trim() == emailAddress.ToLower().Trim());
// there should only be one user in here!
if (users.Count() <= 0)
{
return null;
}
else
{
return users.FirstOrDefault();
}
}
}
return null;
}
Nothing too hardcore. And when the phone calls that method, it throws an EndPointNotFoundException when trying to return the SystemUser object. "There was no endpoint listening at http://localhost:49676/Service1.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details." The inner exception is: "{"The remote server returned an error: NotFound."}"
The generated code that has this problem is here:
public ServiceProxy.UserLoginResponse EndUserLogin(System.IAsyncResult result) {
object[] _args = new object[0];
PhoneApp.ServiceProxy.UserLoginResponse _result = ((PhoneApp.ServiceProxy.UserLoginResponse)(base.EndInvoke("UserLogin", _args, result)));
return _result;
}
It basically looks like it cannot transport the entity? Any ideas? I thought I didn't need to use POCO objects?
Do you have [OperationContract] before Method Name?
http://localhost:49676/Service1.svc is working in browser?
Ok what I did to fix this issue is to right click on blank space in the edmx designer and choose "Add Code Generated Item". From there I picked ADO.NET Self-Tracking Entity Generator. Works beautifully now!