I'm struggling with proper dependencies versioning on releases. I've read in some articles that every change to AssemblyVersion in a library will cause the need of rebuilding all assemblies referencing this library. If it's true I need to be super careful when designing release cycles of dependent assemblies, right?
I wanted to verify the thesis by myself and... well, I noticed it is not the truth at all.
I made a console app which referenced dep1.dll (assembly version 1.0.0.0) and built it. Then I changed dep1.dll to version 2.0.0.0, built it and swapped it with version 1.0.0.0. When running console application I expected error "The assembly dep1.dll with version 1.0.0.0 couldn't be found". And you know what? Nothing special happened, the app used the library like it was targetting that version since the beginning.
ConsoleApp1/Program.cs
using dep1;
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var a = new Class1();
a.Prop1 = "asdf";
Console.WriteLine(a.Prop1);
}
}
public class Implementation : Interface1
{
public int Super { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
}
}
dep1/Class1.cs
namespace dep1
{
public class Class1
{
public string Prop1 { get; set; }
}
public interface Interface1
{
int Super { get; set; }
}
}
As you can see, it's the same with interfaces.
Could you please explain why my test didn't work? This, other SO answers (1) and article by haacked on versioning interfaces really confused me.
Related
I must be overlooking something simple. I'm trying to update a class that once used to compile. I'm mostly swapping out similar classes under different namespaces for new code, cleaning up so to speak.
I have one method, TakeAction, that isn't overriding for me. Parent (abstract) class:
namespace MyNamespace.StandardNoteReceiverService
{
public abstract class NoteReceiverHandler : BaseIntegrationService
{
private Vendor.Sys.Services.ReceiveNoteData _ReceiveNoteData;
public NoteReceiverHandler() {}
public NoteReceiverHandler(Vendor.Sys.Services.ReceiveNoteData receiveNoteData)
{
this._ReceiveNoteData = receiveNoteData;
}
public abstract Vendor.Sys.Services.ReceiveNoteResponse TakeAction(Vendor.Sys.Services.ReceiveNoteData receiveNoteData);
}
}
Implementation of the abstract class:
public class Sys2Handler : NoteReceiverHandler
{
public override Vendor.Sys.Services.ReceiveNoteResponse TakeAction(Vendor.Sys.Services.ReceiveNoteData receiveNoteData)
{
return new Vendor.Sys.Services.ReceiveNoteResponse();
}
Am I just overlooking something? This happens even when I use "Quick Actions and Refactorings" to generate the abstract class.
The following code providing all classes have the same public accessibility compiles perfectly when in single or multiple assemblies.
namespace StandardNoteReceiverService
{
public abstract class NoteReceiverHandler : BaseIntegrationService
{
private Vendor.Sys.Services.ReceiveNoteData _ReceiveNoteData;
public NoteReceiverHandler() { }
public NoteReceiverHandler(Vendor.Sys.Services.ReceiveNoteData receiveNoteData)
{
this._ReceiveNoteData = receiveNoteData;
}
public abstract Vendor.Sys.Services.ReceiveNoteResponse TakeAction(Vendor.Sys.Services.ReceiveNoteData receiveNoteData);
}
public class Sys2Handler : NoteReceiverHandler
{
public override Services.ReceiveNoteResponse TakeAction(Services.ReceiveNoteData receiveNoteData)
{
throw new NotImplementedException();
}
}
}
The only problems which may prevent compilation are different accessibility modifiers or different/conflicting type identity which by .NET is defined as:
Type name, Assembly Name, Assembly Version, Assembly Public Key Signature
Make sure all dependency tree is correct, accessibility is the same and try to recompile. Satisfying the first condition could be a challenge for large projects so perhaps you should use a dependency tree walker to check that all dependencies are correct.
Keep in mind that proper versioning may save you from many similar errors particularly in large code bases.
This can possibly happen if your assemblies are targeting different .net Framework versions.
I'd double check project settings for each assembly.
Our team uses rule "usings inside namespace".
There are two classes:
namespace Foo.Bar
{
public class SomeClass
{
public int CalcSomething()
{
return 1;
}
}
}
and:
namespace Foo
{
using System;
class Program
{
static void Main(string[] args)
{
var someObj = new SomeClass();
Console.WriteLine(someObj.CalcSomething());
}
}
}
Since SomeClass is in Foo.Bar namespace, quick actions menu is offering to resolve namespace, but result differs between VS2015:
and VS2017:
Both versions have Productivity Power Tools installed, if this matters. Both use appropriate PPT extension versions.
How to change resolution behavior for VS2017? I don't need "long namespace", because it's superfluous here.
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!
I have a solution that has many projects in it.
The SqlSmoke.Objects project references the SqlSmoke.Data project.
I set a reference in SqlSmoke.Objects to the solution SqlSmoke.Data. I am then able to compile the entire solution.
However,SqlSmoke.Data does not appear in the intellisense as shown below. However, when I change my namespace to SqlSmoke.Fred, I do see SqlSmoke.Data in intellisense.
I don't see any circular references or other warnings in the Output window that suggest that something else is going on.
What might I look for to understand why I cannot reference objects in the Data project from the Objects project?
using SqlSmoke.Data;
namespace SqlSmoke.Objects
{
public class Class2
{
public void Junk()
{
SqlSmoke.Data. //No intellisense
}
}
}
If I change the Namespace, I get Intellisense:
using SqlSmoke.Data;
namespace SqlSmoke.ObjectsChangedNamespace
{
public class Class2
{
public void Junk()
{
SqlSmoke.Data.CodeObjectData.AddCodeObject("Test"); //Now I see intellisense
}
}
}
You have a [sub]namespace/class name collision. Use:
public void Junk()
{
global::SqlSmoke.Data.
}
and it will work.
namespace PROJ.Service {
public static class ExceptionDatesUpdateService {
public static ExceptionDatesUpdateService()
{
}
public static bool IsServiceRunning() {
return _updateThread != null && _updateThread.IsAlive;
}
}
}
When I try to use a static class above, it says it is not accessible. Why? The reference exists.
using PROJ.Service;
namespace PROJ.admin {
public void ProcessRequest(HttpContext context) {
bool ch = ExceptionDatesUpdateService.IsServiceRunning();
}
}
Thanks everyone. The problem was found. When I solved other errors and compile it. It dissappeared. I am new to c#, sorry for fool question. :)
Assuming you've added the appropriate project reference, one problem I see is that static type initializers cannot have access modifiers. Try this:
public static class ExceptionDatesUpdateService {
static ExceptionDatesUpdateService()
{
}
}
Of course, if there's nothing inside the initializer, you can just remove it entirely.
This is often caused by different .NET framework versions being set in the project properties. For instance, one project may be .NET 3.5 and you're trying to reference a .NET 4.0 project.
It can also be caused by a similar x64 vs x86 mismatch.
Usually the reference itself will have a warning icon next to it.
Check if Target Framework is same in the project properties for both the projects.
namespace PROJ.admin
{
public static class NewClass
{
public void ProcessRequest(HttpContext context)
{
bool ch = ExceptionDatesUpdateService.IsServiceRunning();
}
}
}
Try this is working