following a previous question I posted on StackOverFlow I have the following project structure to my Prism desktop application.
Class Library : Application.Common --> this contains all my DTOs and the service contracts that are defined in my WCF service layer which is an entirely different solution.
Modules: Application.Modules.ServicesModule --> in here I have added links to my WCF implementation using Add Service Reference. I also register the implementations of my types IMyServiceContract is defined in the Application.Common assembly so the initialise method looks as below:-
public void Initialise()
{
_container.RegisterType<IMyService, MyServiceClient>(new InjectionConstructor());
}
Finally I have another module Application.Modules.FunctionalityModule this has a constructor defined as follows
public FunctionalityModule(IMyService myService){}
when the application is trying to resolve the dependency in FunctionalityModule at runtime the following error occurs
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, AccountsSln.Common.ServiceContract.IMyService, is an interface and cannot be constructed. Are you missing a type mapping?
Normally, I have seen this error because a dependency has not been registered but on this occassion I know it has in the ServicesModule. Is this something to do with the registering being in different modules? Are there any other suggestions on how I can implement my project structure to support WCF services in a Prism desktop application?
Thanks
Alex
Edit:
As I wanted to use a Common assembly to define my service contracts I was having problems when using Add Service Reference. It turns out that if you use Add Service Reference the generated code uses the metadata to create client side types. These have the same signature as the ones in the Common assembly but are different. To enable me to use the contracts in the Common assembly I took inspiration from this post http://xaml.geek.nz/working-slightly-smarter-with-wcf. This got me started in the right direction but I think I will have to look into making the code more suited to a production environment.
The problem is that you have not specified the required mapping from the interface to the implementation type. (I prefer using UnityContainerExtensions).
unityContainer.RegisterType < IStudentSearchService, StudentSearchService > ();
You also need to specify module dependencies. Your FunctionalityModule is dependent on the ServicesModule. How this is accomplished depends on how the ModuleCatalog is created.
So either; in Bootstrapper's CreateModuleCatalog use moduleCatalog.AddModule, or decorating the IModules with ModuleAttribute and ModuleDependencyAttribute if using the DirectoryModuleCatalog.
Of course the UnityContainer can be configured through the app.config file.
The generated service proxy classes are partial classes. You might be able to just make them inherit from the IMyService in the Common assembly, by adding something like following in the project where the service references are:
using Application.Common.IMyService;
namespace Application.Modules.ServicesModule
{
public partial class MyServiceClient : Application.Common.IMyService
{
}
}
Related
I would appreciate it if someone would explain to me how .NET references work when a .dll is compiled.
I have two .dll-s, my primary application.dll references my services.dll. The purpose of the services.dll is to provide a decoupled layer for communication with third party services so that changes to the integrations do not affect the application directly.
To achieve this decoupling I have inherited the services primary object exposing and using the new object in the main application:
public class CustomClient : ServiceClient_v1
{
public CustomClient(binding, address) : base (binding, address) {}
}
However, I am finding that when ServiceClient_v1 gets updated to ServiceClient_v2 and I try and just update the services.dll then my application.dll blows up saying:
Could not load type "ServiceClient_v1" from assembly services.dll
So it is still hanging onto a direct reference to that other object that I am trying to hide. I assume this is by design and simply something to do with compilation that I do not understand.
Is there a way to achieve what I want? And why is my method not working?
Since you're deriving CustomClient from ServiceClient_v1 in your application.dll, it will only work with the older version of your services.dll that contains the definition of ServiceClient_v1. As Lasse Vågsæther Karlsen pointed out, the ServiceClient_v1 class becomes part of the public declaration of CustomClient.
I believe you would benefit from applying Dependency Injection and the Liskov substitution principle in your application.
In order to achieve your goal of a truly interchangeable services.dll you need to refactor your architecture removing the dependency of services.dll from application.dll, it should be the other way around.
Define an Interface for your ServiceClient type. Both CustomClient and ServiceClient_v1 must implement this interface.
When you later update the code to use ServiceClient_v2, it should also implement the interface, which will be unchanged. Now everything continues to work without needing to re-complile the application.dll project.
Alternatively, don't rename the ServiceClient type in services.dll when moving from v1 to v2. This is what version control systems like git or SVN or are for.
I have a Wcf Project that is using Linq to Sql -- Serialization Mode = unidirectional with a Wpf Project and a MVC 4 Project.
I have a class library that is holding the dbml for the Linq Classes.
And another Class Library that hold the ViewModels for the Wpf Application
I can add a service reference to the Class Library that holds the ViewModels and access the Wcf methods like normal
client.DoStuff()
Below is the Reference Configuration for the ViewModel C;ass Library
That generates the Correct Reference.Cs
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyWebService/DoStuff", ReplyAction="http://tempuri.org/IMyWebService/DoStuffResponse")]
MyDataProject.Data.DatabaseModels.DoStuff[] DoStuff();
When I create a Web Reference for the Mvc project:
(Same Configuration as above but with a Different ReferenceName)
When executing the same
client.DoStuff()
I get the error -- Method "DoStuff" has 1 parameter but is invoked with 0 arguments.
Then I look at the Reference.cs file
And the method looks like this:
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyWebService/DoStuffResults", ReplyAction="http://tempuri.org/IMyWebService/DoStuffResultsResponse")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
MyWebProject.MyWebSiteReference.DoStuffResultsResponse DoStuffResults(MyWebProject.MyWebSiteReference.DoStuffResultsRequest request);
Unchecking Reuse types in referenced assemblies allows me to access the method normally, but then I get type mismatches.
Is their a step I am missing for using Wcf in Mvc?
EDIT-- I updated the Reference I am using for the Wpf client that generates the correct .cs
Then I tried this per replies
That generates this
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyWebService/DoStuff", ReplyAction="http://tempuri.org/IMyWebService/DoStuffResponse")]
MyWebProject.MyWebSiteReference.DoStuffResponse DoStuff(MyWebProject.MyWebSiteReference.DoStuffRequest request)
I have 2 WCF services (different projects) sharing a class library with a MyExceptions defined.
Both services uses:
[OperationContract]
[FaultContract(typeof(MyException))]
void op();
When I add both references in the client project I get:
Type namespace.MyException already defines a member called MyException
with the same parameter types.
Basically the classes has the same name so the constructor is defined twice.
Any Idea of how to change the Exception namespace?
Please note that:
I am using svcutils
the namespace option doesn't work.
Thanks
Create the proxy using svcutil /reference:SharedLibrary.dll. This way svcutil won't generate classes that it finds in the SharedLibrary.dll, so the client uses the class definitions from the assembly.
Don't forget to add a reference to the DLL in the client project, if you haven't already done so.
Besides the namespace suggestion what can be done is to edit the proxy code generated by SVCUTIL and remove the duplicate code for the MyException class.
The steps:
1. Create a proxy file for Service1.
2. Create a proxy file for Service2.
3. Add the proxies to the client.
4. Compile and it gives error for having MyException already being declared.
5. Edit either one of the proxies and remove the MyException class code.
My first question so hope it is suitable:
Shared interface assembly - I have a 'shared' assembly which has an interface, let's call it IDocRepository. It's marked with [ServiceContract] and there are several [OperationContract]-marked methods.
WCF implementation assemblies - I have two WCF service projects, each referencing the shared assembly, each implementing that interface as a WCF service.
Consumer assembly - Finally, I have a 'client' project, also referencing the shared assembly, with a reference to each of the two WCF services.
However, the service references generated in the consumer assembly derive from an auto-generated version of the interface:
public partial class ExampleClient : System.ServiceModel.ClientBase<SomeNamespace.ExampleSvcRef.IDocRepository>, SomeNamespace.ExampleSvcRef.IDocRepository {
What I expected
I would have hoped that both references would instead automatically inherit the interface I defined, that the consumer/client assembly is also referencing. Kind of like the re-use of classes that it provides for parameter and return types, but for the service interface.
Why
So that I can create an instance of either service reference proxy and cast it to my interface type.
So I could modify the generated code by hand each time, but there should be better way...?
(edit: I do have 'Reuse types in referenced assemblies' and 'Reuse types in all referenced assemblies' options selected for both service references)
"Reuse types in referenced assemblies" only allows you to reuse Data Contracts, not Service Contracts. If you want to share Service Contracts, you don't need to use "Add Service Reference" at all. You can just use ChannelFactory directly.
// Supply the binding and address in code
Binding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress("http://tempuri.org/address");
IServiceContract channel = ChannelFactory<IServiceContract>.CreateChannel(binding, address);
// Or read them from the config file
ChannelFactory<IServiceContract> channelFactory = new ChannelFactory<IServiceContract>();
IServiceContract channel = channelFactory.CreateChannel();
The channel object will also implement ICommunicationObject, so you can cast it if you need to call methods like Open() or Close().
Visual Studio does not support reusing you existing interface when generating the proxy classes for you. Reuse types will not reuse the contract interface as Quartermeister pointed out.
We have solved it with inheritance. Quite similar to the partial class idea above suggested by Jester Software.
This is how we solved it:
In the project of your client just create a service reference as you would have done. Then add a class that serves as the replacement for the client:
internal class MyServiceProxy : MyServiceClient, MyLogicNamespace.IMyService
{}
This class inherits from the generated MyServiceClient but states that that client does implement the original interface.
(I suggest you put them in a folder named "ServiceProxies")
If the MyServiceClient class contains any methods that do not match with the original interface then you can add them in that proxy and do the conversion in code.
After this, just use the MyServiceProxy where you would have used MyServiceClient.
When you create the service reference, there is a box you can tick to make it reuse the shared definitions. Make sure the client project is already referencing the shared assembly, add the service reference again, and check all the options carefully.
If it still doesn't work, check the binding you use. I have a vague recollection that basic HTTP binding won't support re-using of types?
There is another good option, if you want to continue to use the proxy generator for it's limited-but-somewhat-useful functionality... Use a partial class:
namespace <same namespace as generated proxy>
{
public partial class MyClient : <namespace of "real" service contract>.IServiceContract
{
}
}
Ensure that the proxy is generating code the same way your Service Contract is defining it, ie, if it's using 'List', use that option in Configure Service References as well. In other words, make sure your generated Service Interface is exactly equal to your real Service Interface and the above code should work, and to update the reference you use right-click instead of writing code.
[ Updated 25 May 2010 ]
I've recently upgraded from VS2008 to VS2010, and at the same time upgraded to .Net 4.
I've recompiled an existing solution of mine and I'm encountering a Cast exception I did not have before.
The structure of the code is simple (although the actual implementation somewhat more complicated).
Basically I have:
public class SomeClass : ISomeClass
{
// Stuff
}
public static class ClassFactory
{
public static IInterface GetClassInstance<IInterface>(Type classType)
{
return (IInterface)Activator.CreateInstance(classType); // This throws a cast exception
}
}
// Call the factory with:
ISomeClass anInstance = ClassFactory.GetClassInstance<ISomeClass>(typeof(SomeClass));
Ignore the 'sensibleness' of the above - its provides just a representation of the issue rather than the specifics of what I'm doing (e.g. constructor parameters have been removed).
The marked line throws the exception:
Unable to cast object of type
'Namespace.SomeClass' to type
'Namespace.ISomeClass'.
I suspect it may have something to do with the additional DotNet security (and in particular, explicit loading of assemblies, as this is something my app does).
The reason I suspect this is that I have had to add to the config file the setting:
<runtime>
<loadFromRemoteSources enabled="true" />
</runtime>
.. but I'm unsure if this is related.
Update
I see (from comments) that my basic code does not reproduce the issue by itself. Not surprising I suppose. It's going to be tricky to identify which part of a largish 3-tier CQS system is relevant to this problem.
One issue might be that there are multiple assemblies involved. My static class is actually a factory provider, and the 'SomeClass' is a class factory (relevant in that the factories are 'registered' within the app via explicit assembly/type loading - see below) .
Upfront I use reflection to 'register' all factories (i.e. classes that implement a particular interface) and that I do this when the app starts by identifying the relevant assemblies, loading them and adding them to a cache using (in essence):
Loop over (file in files)
{
Assembly assembly = Assembly.LoadFile(file);
baseAssemblyList.Add(assembly);
}
Then I cache the available types in these assemblies with:
foreach (Assembly assembly in _loadedAssemblyList)
{
Type[] assemblyTypes = assembly.GetTypes();
_loadedTypesCache.AddRange(assemblyTypes);
}
And then I use this cache to do a variety of reflection operations, including 'registering' of factories, which involves looping through all loaded (cached) types and finding those that implement the (base) Factory interface.
I've experienced what may be a similar problem in the past (.Net 3.5, so not exactly the same) with an architecture that involved dynamically creating classes on the server and streaming the compiled binary of those classes to the client app. The problem came when trying to deserialize an instance of the dynamic class on the client from a remote call: the exception said the class type was not know, even though the source and destination types were exactly the same name (including namespace). Basically the cross boundry versions of the class were not recognised as being the same. I solved that by intercepting the deserialization process and explicitly defining the deseriazation class type in the context of the local assemblies.
This experience is what makes me think the types are considered mismatched because (somehow) the interface of the actual SomeClass object, and the interface of passed into the Generic method are not considered the same type.
So (possibly) my question for those more knowledgable about C#/DotNet is: How does the class loading work that somehow my app thinks there are two versions/types of the interface type and how can I fix that (keeping in mind its a DotNet 3.5 vs 4 issue as it worked before my upgrade) ?
[ whew ... anyone who got here is quite patient .. thanks ]
I would say yes that it has something to do either with the runtime loading of assemblies, or with the upgrade conversion, I used this code in a new project and had no issues. Can you provide more code to replicate the error?
The 'quick' (ITO implementation, not ITO finding it) solution was to stop the shadow copy of my app's DLLs.
This is done by modifying the ASP.Net app's Web.Config file as follows:
In section 'configuration/web.settings', add setting:
<hostingEnvironment shadowCopyBinAssemblies="false" />