wcf CS0012 puzzle with nested type - c#

Sorry if this is obvious but I am pulling my hair over this issue: I have a class library ClassLibrary1 that defines Class1, and a WCF Service Library WcfServiceLibrary1 referencing ClassLibrary1 that defines a class Response in which Class1 is nested:
public class Response
{
public string Message { get; set; }
public Class1 Value { get; set; }
}
Then I added a simple console application as client referencing WcfServiceLibrary1 (but not ClassLibrary1, to simulate separation between business logic and client logic). However I cannot compile WcfServiceLibrary1 as I get error "CS0012 The type 'Class1' is defined in an assembly that is not referenced. You must add a reference to assembly 'ClassLibrary1..."
What am I missing? Thanks
Class1.cs:
namespace ClassLibrary1
{
public class Class1
{
public int SomeInt { get; set; }
}
}
IService1.cs:
namespace WcfServiceLibrary1
{
[ServiceContract]
public interface IService1
{
[OperationContract]
Response ConvertToClass(int value);
[OperationContract]
Class1 AltConvertToClass(int value);
}
public class Response
{
public string Message { get; set; }
public Class1 Value { get; set; }
}
}
Service1.cs:
namespace WcfServiceLibrary1
{
public class Service1 : IService1
{
public Response ConvertToClass(int value)
{
return new Response() {Message = "Success", Value = new Class1() {SomeInt = value}};
}
public Class1 AltConvertToClass(int value)
{
return new Class1() {SomeInt = value};
}
}
}
Program.cs:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var client = new ServiceReference1.Service1Client();
client.Open();
Console.Write("Enter number:");
var s = Console.ReadLine();
var n = int.Parse(s);
var c = client.ConvertToClass(n);
Console.WriteLine($"Result: Message = {c.Message}, Value = {c.Value}"); //CS0012
var c2 = client.AltConvertToClass(n);
Console.WriteLine($"Result: {c2.SomeInt}");
Console.WriteLine("\nPress enter...");
Console.ReadLine();
}
}
}

Exactly what the error says.
Regardless of your design intentions, by referencing Class1 in WcfServiceLibrary1, you have made ClassLibrary1 a dependency of WcfServiceLibrary1.
No other component can reference WcfServiceLibrary1 without also referencing ClassLibrary1.
You will have to revisit your design.

Update 1
After looking at your solution, the issue is that you are generating a service reference, which creates copies of the classes that are needed by your service. Open ConsoleApplication1 -> Service References -> ServiceReference1 -> Reference.svcmap -> Reference.cs and you will see that it has generated a class called Class1 in the namespace ConsoleApplication1.ServiceReference1. This was done because the project has not referenced your ClassLibrary1 solution. It did not generate the code for the Response object as this has already been referenced in your console project. So the result is that:
The call AltConvertToClass returns an object of type ConsoleApplication1.ServiceReference1.Class1
The call ConvertToClass returns an object of type WcfServiceLibrary1.Response, which contains an object of type ClassLibrary1.Class1 (which is different to the one above), resulting in a compiler error
I suggest you follow the tutorial I linked to below, as that IMHO is the correct way to do service oriented architecture. Leave service references alone - it ends up duplicating code.
Otherwise, you can fix your code as follows:
Create a contract project and move the interface (IService1) and DTOs (your Response class is a DTO, and as you are returning Class1, that is a DTO too) to this project.
Service project containing the implementation (Service1) should reference your contract class
Console application should reference your contract project
Update your service reference
Original
You still need to reference any projects whose classes you use. As Class1 is used in your console application, it needs to reference ClassLibrary1.
If you want to separate your business logic from your client application, you cannot reference any classes in your business logic classes in your client application. If you want to return any objects in your Response class, you should rather create a contract library to contain your DTOs (Data-transfer objects) and map your domain classes to DTO classes, and reference the contract project in both the server and the client.
I wrote a tutorial a while ago about this architecture at http://lourenco.co.za/blog/2013/08/wcf-windows-service-using-topshelf-and-servicemodelex/ . Disclaimer - I wrote this tutorial!

This error comes from ConsoleApplication1 (the client) referencing WcfServiceLibrary1 (the host), causing the automatically generated service code in [ConsoleApplication1 -> Service References -> ServiceReference1 -> Reference.svcmap -> Reference.cs] to reuse WcfServiceLibrary1.Response (which relies on ClassLibrary1.Class1 whence CS0012) yet otherwise creates ServiceReference1.Class1 to deal with the AltConvertToClass method.
The solution is to remove the reference from ConsoleApplication1 (the client) to WcfServiceLibrary1 (the host), which makes perfect sense since the two assemblies will typically be run on separate machines.
Thanks everyone for your contributions!

Related

Execute code in a class library when you do not have a reference to that class library

Say I have a class library like this:
using ClassLibrary2;
namespace ClassLibrary1
{
public class Class1 : IClass1
{
public string SayHello()
{
return "Hello";
}
}
}
and a class library like this:
namespace ClassLibrary2
{
public interface IClass1
{
string SayHello();
}
public class Class3
{
IClass1 _class1;
public Class3(IClass1 class1)
{
_class1 = class1;
string test = _class1.SayHello();
}
}
}
and a program like this:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
IClass1 class1 = new Class1();
Class3 class3 = new Class3(class1);
}
}
}
ClassLibrary1 references ClassLibrary2. WindowsFormsApplication1 references ClassLibrary1 and ClassLibrary2.
The program finishes. ClassLibrary2 is able to execute code from ClassLibrary1 even though ClassLibrary2 does not reference ClassLibrary1. What is this technique called? I want to read more about it and use it. I realise it is polymorphism. I am referring to the technique of executing code in a class library without a dependancy.
You discovered the D in SOLID: Dependency inversion principle.
Program against interfaces, not implementations.
You are not executing code from ClassLibrary1 in ClassLibrary2, you are invoking functionality described in an interface that you defined in ClassLibrary2 itself.
At runtime, the implementation of what you invoke may be provided by ClassLibrary12635.
One example where this can be really useful is if I define an interface for, say, a DAL (Data access layer) component in a separate library, defining the functionality of that DAL component. I can implement business logic in a business logic layer (BLL) using that interface (I need to reference the library with the interface).
For my DAL itself I can implement different implementations, and create two different libraries - for instance one that uses local, client side storage, and another that uses a centralised database. I can then substitute one DAL library for the other without having to change a single line of code in my business logic.

C# internal Access Specifiers,

I have Created one ConsoleApplication to understand Access Specifiers.
Below is my code for internal, I can access this class from outside the Assembly.
namespace Assembly_1 //This is first assembly.
{
public class Base
{
//internal class
internal class B
{
public static void fnB()
{
Console.WriteLine("fnB");
}
}
}
}
namespace Assembly_2 //This is second assembly.
{
public class Derived : Assembly_1.Base
{
public class D
{
public void fnD()
{
B.fnB();//how can I access this class?
}
}
}
}
And this is where I am Accessing it.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Assembly_2.Derived.D d = new Assembly_2.Derived.D();
d.fnD();
}
}
}
My Question
Right now I can Access Class B and it's methods like fnB() in Derived.
Everything works fine. but How?
How can I access the B Class outside Assembly_1?
As I worte in the comments:
You are confusing the namespace and assembly terms.
You can read about it here:(Assemblies and Namespace)
Many namespaces can be defined in a single assembly.
If you would like to check and understand the internal modifier,
then you would have to create a new class library project (that will compile into a different assembly), define the Base class there
and add a reference to it in your main console application.
Then you will see that you don't have access to it anymore and the code will not compile.
How can I access the B Class outside Assembly_1?
Because you're confusing namespaces and assemblies. An assembly is a collection of one or more namespaces, contained within a .dll or .exe file.
See also: MSDN: Assemblies in the Common Language Runtime and Understanding and Using Assemblies and Namespaces in .NET.
What you call Assembly_1 and Assembly_2 are namespaces within the same assembly.
Because internal members are visible within the same assembly, you can use Assembly_1.B from Assembly_2.D, because both namespaces reside in the same assembly.

Using referenced complex types in WCF clients

I'm kinda new to C#, and I've got a problem with a DataMember in a WCF application:
The DataMember in question is a List of instances of a class implementing an interface, let's call this class "classA", in "assemblyA", implementing "interfaceA".
The "main" data object (that has this DataMember) which is passed from server to client via WCF is defined as "classB" and lies in assembly "assemblyB" which is referenced in both server and client.
AssemblyB has a refence to assemblyA. All is fine so far.
Now the client (in "assemblyC") connects to the service that passes assemblyB DataContract objects via WCF, but asseblyC has NO reference to assemblyA (and shouldn't have!). All is still fine, serialization and deserialization work fine, but:
As soon as I try to use classA objects in assemblyC, C# complains it doesn't know the type.
Is there any way to import interfaceA into assemblyC without referencing assemblyA? I tried definining an interface in C that inherits from intefaceA ("interfaceCA") and cast to that in assemblyC… but no luck, C# still complains about the missing reference to assemblyA.
I can't move interfaceA from assemblyA to assemblyB, since assemblyA has to work without a reference to assemblyB, and I don't want to reference assemblyA in assemblyC, because assemblyC is not even supposed to know about assemblyA… apart from that one Data member.
And as far as I know, in C# I can't forcibly cast to a copy of interfaceA defined in assemblyB… so, anyone an idea how I can get it over to assemblyC?
Let's give you a simple pseudo code snippet for demonstration purposes:
// assemblyA
public interface iA
{
string Stuff { get; }
}
[DataContract]
public class A : iA
{
[DataMember]
public string Stuff { get { return "Stuff"; } }
}
// assemblyB, references assemblyA
[DataContract]
public class B
{
[DataMember]
public int Num { get; protected set; }
[DataMember]
public List<A> StuffContainers { get; protected set; }
}
// assemblyC, references assemblyB
public class C
{
public void ReceiveData(B data)
{
Console.WriteLine(data.Num); // all fine
// the following line shows an error
foreach (var stuffContainer in data.StuffContainers)
{
Console.WriteLine(stuffContainer.Stuff);
}
// same here, of course since C# can't resolve namespaceA and/or iA
foreach (namespaceA.iA stuffContainer in data.StuffContainers)
{
Console.WriteLine(stuffContainer.Stuff);
}
// same here of course
List<namespaceA.iA> sC = (List<namespaceA.iA>)data.StuffContainers;
foreach (namespaceA.iA stuffContainer in sC)
{
Console.WriteLine(stuffContainer.Stuff);
}
}
}
Hope this makes it clear enough… it's my first own SO question ever! ;)

Add reference Error in c# console app

I am creating a Console App in C# using VS2010. It is based in 3-Layer Architecture containing three layers
PMS.UI
PMS.DAL
PMS.BL
To remove Circular Dependency between PMS.DAL and PMS.BL I added an extra layer PMS.Service.
I created a Vehicle class in PMS.BL which implements interface IVehicle from PMS.Service.
I added reference of PMS.Service in both DAL and BL.
Now UI calls AddNewVehicle() method of Vehicle class of BL which implements IVehicle
BL calls AddNewVehicle(IVehicle obj) method of VehicleDao in PMS.DAL...
All working fine but at time of build Compiler says to add reference of PMS.Service in PMS.UI.
PMS.UI doesn't implement any interface of PMS.Service but calls AddNewVehicle() method of Vehicle class of PMS.BL which implements IVehicle.
Is it necessary to add reference of PMS.Service to PMS.UI only if it creates instance of Vehicle Class of PMS.BL which implements IVehicle present in PMS.Service..
Please help me I am new to use Interface in c#...
Thankyou Guys for your answers but i am still confused. I will present my code here.I have added all four layers as different c sharp class library(different layers).
1)PMS.UI(Added reference of PMS.BL)
Program.cs
using System;
using PMS.BL;
namespace PMS.APP
{
class Program
{
static void Main()
{
var vBo = new VehicleBo();//Compiler Says Add reference of PMS.Service here.Why is it necessary to add Reference of it??
vbo.VehicleNumber = "BA1PA 1212";
vbo.VehicleType = "Bike";
vbo.SaveNewVehicle();
}
}
}
2)PMS.BL(Added reference of PMS.DAL and PMS.Service)
VehicleBO.cs
using PMS.DAL;
using PMS.Service;
namespace PMS.BL
{
public class VehicleBo : IVehicle
{
public string VehicleNumber { get; set; }
public string VehicleType { get; set; }
public void SaveNewVehicle()
{
var vDao = new VehicleDao();
vDao.SaveNewVehicle(this);
}
}
}
3)PMS.DAL(Added reference of PMS.Service)
using PMS.Service;
namespace PMS.DAL
{
public class VehicleDao
{
public void SaveNewVehicle(IVehicle obj)
{
//code to insert in database
}
}
}
4)PMS.Service
IVehicle.cs
namespace PMS.Service
{
public interface IVehicle
{
string VehicleNumber { get; set; }
string VehicleType { get; set; }
void SaveNewVehicle();
}
}
With the given details (and no code). This is what I understand.
PMS.Service (IVehicle.cs)
PMS.BL (Vehicle : IVehicle)
In this scenario, if you are exposing Vehicle, you will have to add reference to PMS.Service also. In any case, having model interfaces/contact in service implementation does not look right. I would rather consider creating PMS.Contracts and have my model/service contracts there.
Hope that helps.
I think that you have an architecture problem. Basically, if you are in three layer, this is the good way :
IHM => BLL => DAL
Core
Core is a project contains tools function (format date, number etc.) and your interface.
The dependencies : IHM reference BLL / BLL reference DAL. An all of these reference Core. Core have no dependency.
I'm beginner like you with interface. Here the way i'll choose if i have to do it :
4 projects :
Core
BLL (depecencies DAL - Core)
DAL (depecencies Core)
IHM (depecencies BLL - Core)
In Core : Two things : An Interface IVehicle and a class that implement this class call Vehicle
Because we need to use a DAL, i don't know how to do for not use Core.Vehicle. An abstract class is not good because if DAL need to return a "IVehicule" object, we need to implement an object and we can't implement an Abstract or Interface.
In BLL : Two objects : Car and Truck that implement Core.Vehicule
In DAL : One object : Vehicule with a method for return a Core.Vehicule
In IHM : A call of BLL.Car
And it's doing the thing...
EDIT :
I've post a question like yours : POO and Interface (in C#)
Hope it help you.

Activator.CreateInstance: Dynamic Instantiation of Classes

I am designing a loosely-coupled structure. I want to call classes from different assemblies/namespaces via a code which is represented by a String. My design is, each of client's business rules is on different assemblies and not dependent on each other (ONE client is to ONE DLL ratio) so that when I made an update on business rules of 1 client, it would not affect the others. My attention now is on using Factory Design and using Activator.CreateInstance() Method.
This is the project setup (2+n DLL's)
namespace Foundation; // where the interfaces/abstract resides
namespace Factory; // has dependency on Foundation assembly
namespace Client1; // client1's DLL, no dependency
namespace Client2; // client2's DLL, no dependency
The UI // only referenced to the Foundation and Factory not the Clients
The actual code
namespace Foundation
{
public interface IBusinessRules
{
string GetBusinessRule();
}
}
namespace Client1 //DLL for client 1
{
public class BusinessRules : Foundation.IBusinessRules
{
public string GetBusinessRule()
{
return "Client1 Business Rule";
}
}
}
namespace Client2 //DLL for client 2
{
public class BusinessRules : Foundation.IBusinessRules
{
public string GetBusinessRule()
{
return "Client2 Business Rule";
}
}
}
namespace Factory
{
public static class Invoker<T> where T: Foundation.IBusinessRules
{
public static T FetchInstance(string clientCode)
{
return (T)Activator.CreateInstance(Type.GetType(clientCode));
}
}
}
//sample implementation that generates unhandled Exception
using Factory;
using Foundation;
static void Main(string[] args)
{
//the parameter is maintained in the database
IBusinessRules objClient1 = Invoker<IBusinessRules>.FetchInstance("Client1");
//should call Client1.BusinessRules method
Console.WriteLine(objClient.GetBusinessRule());
Console.Read();
objClient = Invoker<IBusinessRules>.FetchInstance("Client2");
//should call Client2.BusinessRules method
Console.WriteLine(objClient.GetBusinessRule());
Console.Read();
}
Any idea why my sample doesn't work? And any suggestion to improve the design?
Thanks in advance.
How about using
Expression.Lambda
anyone?
If you use FetchInstance("Client.BusinessRules") your code works, IF everything is in the same assembly. If it's not (as per your design) you need to give an AssemblyQualifiedName.
I would do the design differently though. Keep your call with just "Client1" as Parameter but change the implementation of the Factory. Dynamically load the assembly for the given client (with Assembly.Load() or Assembly.LoadFrom()), then use clientAssembly.CreateInstance() to istantiate your type.
Edit: Crude code sample:
namespace Factory
{
public static class Invoker<T> where T: IBusinessRules
{
public static T FetchInstance(string clientCode)
{
var clientAssembly = Assembly.LoadFrom(clientCode + ".dll");
return (T)clientAssembly.CreateInstance(clientCode+".BusinessRules");
}
}
}
If you dont't know the class name in the client-dll, you have to search for an applicable Type, for example with clientAssembly.GetTypes().
Thanks to your help guys i finally Got it! I just modify the Factory
namespace Factory
{
public static class Invoker<T> where T : Foundation.IBusinessRules
{
public static T FetchInstance(string clientCode)
{
Type objType = Type.GetType(clientCode + ".BusinessRules," + clientCode);
return (T)Activator.CreateInstance(objType);
}
}
But I wonder about its effeciency (performance hit) because it uses Reflection..
You need to use the full name of the class.
for example:
Type.GetType("System.Collections.Generic.Dictionary`2[System.String,[MyType,MyAssembly]]")
If you are loading the type from an external assembly, I would recommend using Activator.CreateInstanceFrom.
var typeReference = Activator.CreateInstanceFrom(assemblyPath, fullyQualifiedClassName);
return typeReference.Unwrap() as T;
If you want to be able to add business rules as dlls after deployment and create them at runtime, I suggest you have a business rules folder under you app, load all dlls in that app, search for all types that implement of IBusinessRules in each dll using reflection. Given that you now have handles on the types, creating one based on name would be easy and your project would scale out.
Either that, or pass the assembly qualified name of the classes to your methods.

Categories

Resources