Using wcf services in S#arp Architecture project
I have a sharp architecture project and I am making use of ApplicationServices in it as well.
There is requirement to provide a winform client that will use a wcf service. The wcf service will in turn use the ApplicationServices. I have not started working on the winform client yet but I am working on the wcf service.
Following the Northwind sample. I have created a "Wcf Service library" project and a "Wcf Service Application" project in my solution.
I am new to wcf but i know all the basics and have worked with web services alot in the past. I have following questions:-
1) I would like to know why there is a need of two projects, wcf library and wcf application?
2) I have noticed that the ITerritoriesWcfService interface in the Northwind sample inherits ICloseableAndAbortable.
public interface ITerritoriesWcfService : ICloseableAndAbortable
What is the purpose of ICloseableAndAbortable?
3) There is another class TerritoriesWcfServiceClient
public partial class TerritoriesWcfServiceClient : ClientBase<ITerritoriesWcfService>, ITerritoriesWcfService
What is the purpose of this class?
4) In the TerritoriesService.svc file, what is the purpose of Factory="SharpArch.Wcf.NHibernate.ServiceHostFactory, SharpArch.Wcf" ? Usually in a normal wcf service application, I use codebehind attribute, but since the .cs file actually resides int the wcf service library project, I would like to know what following code is doing?
<%@ ServiceHost Language="C#" Debug="true"
Service="Northwind.Wcf.TerritoriesWcfService"
Factory="SharpArch.Wcf.NHibernate.ServiceHostFactory, SharpArch.Wcf" %>
Even if I remove the above Factory attribute, I can still run the service app project and test the service using WcfTestClient utility.
6) When i run my service and using WcfTestClient If I r开发者_如何学Goun a method twice that accesses a repository, then on the second call, I get an ObjectDisposedException.
{"Session is closed!\r\nObject name: 'ISession'."}
I believe the NHibernate Session is getting disposed after the first call. How can reinitialise for each call or should I keep it open? I would like to know the best practice?
7) Also If I run the Northwind.Wcf.Web project and click on TerritoriesService.svc file on the Directory Listing screen, I get the following error
{"Method 'Generate' in type 'Northwind.Data.NHibernateMaps.AutoPersistenceModelGenerator' from assembly 'Northwind.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.":"Northwind.Data.NHibernateMaps.AutoPersistenceModelGenerator"}
I don't understand why is it throwing this error, when i already got the method and the Northwind.Web works fine too.
Awaiting Nabeel
1) Strictly, you can combine the WCF library and the WCF application in one assembly. This would mean that you would combine the contracts and the implementations in one assembly.
If you are using svcutil.exe or Visual Studio (which uses svcutil.exe in turn) to generate proxy classes for your client, you'd be fine because the proxy classes are generated from discovery of your services.
If however, you want to use your own classes for transport, which is quite common in DTO scenarios and the like, you'd need to reference a shared library from both the client and the server. If that shared library would be your combined library/application assembly, the client would get the application implementation in scope (because it references the assembly that contains the contracts) and that's really not something you'd want. The client needs to know as little as possible about the server, just as much as the contracts expose -- that's what the contracts are for in the first place.
I think it is best practice to separate interfaces/contracts from implementation anyway because it leads to better separation of concerns. It's just that most parts of your solution don't need (and shouldn't) know HOW something is done, just WHAT that something can do. There are many more advantages over this, such as improved testability.
2) Taken from the code documentation of ICloseableAndAbortable:
"When implemented by your WCF contracts, they are then interchangable with WCF client proxies. This makes it simpler to use dependency injection and to mock the WCF services without having to worry about if it's a WCF client when you go to close/abort it.".
I think that says it all.
3) The client class is, like the code documentation says, a strongly typed client proxy. It can be used by clients to talk to the server, providing a strongly typed class that has members that correspond to the service operations that can be called on the server.
The advantage of this class is that you don't need to use the svcutil.exe generated proxy classes. This what they mean by not having to configure it via WCF configuration. This allows you to ship proxy classes to your clients so they can immediately talk to your server instead of generating proxy classes first. It allows for more control as well, changing the code that is generated by the proxy class is really not something you'd want to do.
This again is a good reason to put the interfaces/contracts in a separate assembly because you don't want to ship the service implementation code to your clients.
4) The service host factory creates a service instance based on the provided service type. This can come in handy if you want to put the service code somewhere other than in the code behind file. You'd also need it if you are using Depency Injection, you'd provide the service contract interface as the type and the SharpArch.Wcf service host factory resolves it to the correct implementation class type by means of the DI framework (Castle Windsor in SA). You can think of this as a means of getting hold of a service implementation while not caring about where it actually is coming from.
In this case, the service will run when you remove the factory attribute, because the default factory is able to resolve the service type. You're bypassing on stuff like DI and session management though, exactly that what makes SA valueable.
5) I'll have to skip this one because apparently there is no question number 5 :-)
6) As in the Northwind sample project, you are probably using the ServiceHostFactory
that comes with SA. With this service host factory, each created service instance is extended by a behavior that closes the NHibernate session directly after it's called. That okay by itself but chances are that your proxy clients are not managed in a transient way by Castle Windsor. Therefore instances get reused, including the closed sessions they (still) contain. Decorate your client proxy classes with the Transient
attribute (Castle.Core.TransientAttribute
) and Castle Windsor will create a fresh instance every time a service call is performed.
Apparently, there is a second way to solve this but it requires modification of the S#arpArchitecture code base. See WCF connections which process more than one request fail because the nhibernate session is closed and isn't re-opened. on GitHub.
7) I'm sorry, I seriously have no idea. I might look into this later.
精彩评论