Reputation: 5280
Having a lot of trouble with a dotnet core c# console application using Visual Studio 2017RC (27th Jan build) when trying to load interfaces from a separate DLL (project is part of same solution). I followed the Visual Studio 2017RC instructions for setting up for dotnet core here: https://www.microsoft.com/net/core#windowsvs2017
Main application:
public class Core
{
public static void Main(string[] args)
{
Console.WriteLine("Starting...");
// Setup PubSub
var pubSub = new PubSub();
}
}
public class PubSub : IPubSub
{
// Subscription table
private static ConcurrentDictionary<ChannelKey, ChannelSub> subscriptions = new ConcurrentDictionary<ChannelKey, ChannelSub>();
// User group table
private static ConcurrentDictionary<string, List<string>> clientGroups = new ConcurrentDictionary<string, List<string>>();
public PubSub()
{
try
{
List<string> users = new List<string>();
clientGroups["ADMINS"] = new List<string> { "PubSub.myClient" };
AddUpdChannel(new ChannelKey
{
network = Core.networkName,
category = "LIGHTING",
className = "CBUS",
instance = "MASTERCOCOON"
}, new ChannelSub
{
auth = new List<AccessAttribs>
{
new AccessAttribs
{
name = "ADMINS",
access = "RW"
}
},
clients = new List<AccessAttribs>
{
new AccessAttribs
{
name = "PubSub.myClient",
access = "RW"
}
}
});
Subscribe("myClient", new ChannelKey
{
network = Core.networkName,
category = "LIGHTING",
className = "CBUS",
instance = "MASTERCOCOON"
});
}
catch (Exception ex)
{
throw ex;
}
}
public bool Publish(string clientName, ChannelKey channel, string message, [CallerFilePath] string caller = "")
{
Logger.LogInformation("Client: " + clientName + " published to: " + channel.instance + " TEST");
return true;
}
// Channels must be created before subscribed to.
public bool AddUpdChannel(ChannelKey channel, ChannelSub channelSub, [CallerMemberName] string caller = "")
{
channelSub.author = caller; // Enforce author as caller, regardless of setting passed.
subscriptions[channel] = channelSub;
return true;
}
// Subscribe to channel for Ext/Plug.Client. Return null if channel does not exist else return access rights ("", R, RW) and update any old entries or add new
public string Subscribe(string clientName, ChannelKey channel, [CallerFilePath] string caller = "")
{
string access = "";
var fullClientName = Path.GetFileNameWithoutExtension(caller) + "." + clientName;
if (subscriptions.TryGetValue(channel, out var subscription)) // Get channel subscription info
{
foreach (var subGroup in subscription.auth) // Get access rights for group client is a member of
{
clientGroups.TryGetValue(subGroup.name, out var clientGroup); // Lookup clients associated with group
if (clientGroup.Contains(fullClientName))
{
access = subGroup.access;
if (subGroup.access == "RW") break; // RW access takes precidence if user is a member of multiple groups
}
}
if (access != "") // Some access allowed so setup
{
var newAccess = new AccessAttribs
{
name = fullClientName,
access = access
};
var exists = subscription.clients.FindIndex(x => x.name == fullClientName); // Look for fullClientName already in list (assume there could be any access strings)
if (exists != -1)
{
subscription.clients[exists] = newAccess; // Update if existing
}
else
{
subscription.clients.Add(newAccess); // Add if new
}
subscriptions[channel] = subscription; // Update subscription with new client access info
}
return access;
}
return null; // subscription does not exist
}
}
The interfaces are defined in a separate project as follows:
namespace Interfaces
{
public interface IExtension
{
string ExtStart(IPubSub myHost);
string ExtStop(string param);
}
public interface IPubSub
{
bool AddUpdChannel(ChannelKey channel, ChannelSub channelSub, [CallerMemberName] string caller = "");
string Subscribe(string clientName, ChannelKey channel, [CallerFilePath] string caller = "");
bool Publish(string clientName, ChannelKey channel, string message, [CallerFilePath] string caller = "");
}
public struct ChannelKey
{
public string network;
public string category;
public string className;
public string instance;
}
public struct AccessAttribs
{
public string name;
public string access;
}
public class ChannelSub
{
public bool active = true;
public string desc = "";
public string type = "GENERIC";
public string author = "";
public List<AccessAttribs> clients = new List<AccessAttribs>(); // List of clients subscribed & their access rights. This is set when subscribing to enable fast lookup when processing messages
public List<AccessAttribs> auth = new List<AccessAttribs>(); // When subscribing, clients must be a member of one of these groups & will get the access rights of that group
public List<KeyValuePair<string, string>> attribs = new List<KeyValuePair<string, string>>();
}
Solution builds fine, and intellisense finds all the interface definitions in the DLL, so it must be finding the file. I have clean/rebuilt/checked the file location many times and it is fine. Also I can cut/paste this code into a non Core .NET project and it works fine.
The error reported when first starting in debug mode is:
System.IO.FileNotFoundException 'Could not load file or assembly Commons, Version=1.0.0.0,
culture=neutral, PublicKeyToken=null". The system cannot find the file specified.
csproj for the main project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="Commons">
<HintPath>..\Commons\bin\Debug\netcoreapp1.1\Commons.dll</HintPath>
<Private>true</Private>
</Reference>
</ItemGroup>
</Project>
csproj for the interface DLL (Commons.DLL)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
</Project>
I have rebuilt this project many times, reinstalled VS 2017RC several times and I can't get rid of the file not found error for the interface reference DLL.
Upvotes: 1
Views: 2544
Reputation: 10025
It seems that you are missing <PackageReference Include="Microsoft.NETCore.App" Version="1.0.1" />
before Microsoft.Extensions.Configuration
in ItemGroup
.
And I recommend you to reference project itself instead of referencing debug
dll. Result csproj
should look like:
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
<EmbeddedResource Include="**\*.resx" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.App" Version="1.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Commons\Commons.csproj" />
</ItemGroup>
</Project>
Your Common
project is library so it should't be a netcoreapp
, but it should be .Net Standard library. This is how its csproj
should look like:
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
<EmbeddedResource Include="**\*.resx" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NETStandard.Library" Version="1.6" />
</ItemGroup>
</Project>
Now you should be able to successfully compile and run the code.
Here is sample repository: https://github.com/Pzixel/Question41918456
Upvotes: 1