I have written a console application in C# /VS2008. In that I have multiple classes declared without specifying any accessibility modifier. Like
Namespace MyNamespace
{
Class MyClass
{
..
}
}
Now I added a new console application for testing purpose. I added reference to NUnit framework dll. And then a reference to my main project dll. But when I try to create an object of MyClass into my TestFixture class, then I get an error like "MyNamespace.MyClass is inaccessible due to its protection level"
Do I need to create my class as public? But what if my project cannot afford it?
The class needs to be public if you want it to be accessible from another assembly:
namespace MyNamespace
{
public class MyClass
{
}
}
If your project cannot afford it you may take a look at [InternalsVisibleTo] attribute.
Related
I have a Winforms application that is designed to integrate with external software packages. This application reads data from these packages and pushes it to our server where users log in and use our application (App).
public abstract ClassToImplement
{
public abstract void DefinedMethod1();
public abstract void DefinedMethod2();
}
When we designed the application it was intended to do 95% of the integration work with the remaining 5% (implementation class / App2) being developed by a consultant who's familiar with the 3rd party software.
public class Implemented : ClassToImplement{
public override void DefinedMethod1(...);
public override void DefinedMethod2(...);
}
The "App" outputs a Class Library which is then referenced in the Implementation (App2). In our design we created an Abstract Class and defined the methods. The idea was that the consultant would download the repo for the implementation class and include the App as a reference. They would then write the necessary code for the methods they're implementing, compile and "voila!"
For obvious reasons I don't want to share the source project with external developers, otherwise I'd just share the full solution and use a single app, and, while I know they can see a lot with the DLL reference, it is just easier for us to control everything.
The problem comes with App: the main application algorithm needs to instantiate the implementation class and then the program runs perfectly.
in Form1.cs of App:
ClassToImplement impObj = new Implemented();
impObj.DefinedMethod1();
impObj.DefinedMethod2();
The challenge I'm having is that I cannot build "App" to output a DLL without instantiating the Class. I cannot instantiate the Implemented Class as I haven't got the code (yet).
It would be great to know how to go about achieving this sort of abstraction with a dependancy on (yet) unwritten code and also, what is the technical term for what I'm trying to do?
To make it just "work" use a Func which returns an instance of the abstract class.
In your secret repo:
//Your "App" DLL Project
public abstract class ClassToImplement
{
public abstract void DefinedMethod1();
public abstract void DefinedMethod2();
}
public class App : Form
{
public App(Func<ClassToImplement> initiator)
{
InitializeComponent();
ClassToImplement ci = initiator.Invoke();
ci.DefinedMethod1();
ci.DefinedMethod2();
}
}
//This is in a separate project which will be your startup project internally
public class Dummy : ClassToImplement
{
public override void DefinedMethod1(){}
public override void DefinedMethod2(){}
}
public class Program
{
public static void Main()
{
Application.Run(new App(()=> new Dummy()));
}
}
In the repo shared with the consultant:
// In the repo which is shared with the consultant
// This will be the startup project on the build server, and when the consultant is testing.
public class Implementation : ClassToImplement
{
public override void DefinedMethod1(){}
public override void DefinedMethod2(){}
}
public class Program
{
public static void Main()
{
Application.Run(new App(()=> new Implementation()));
}
}
On your build server, you can pull from both the repos, and set the startup project as the one given to the consultant. But when you are testing and developing internally, you set the startup project to your version with an implementation that does nothing.
As a side note, if you think what you are doing needs to be protected from consultants who have signed a confidentiality agreement, make sure to obfuscate when you do a release.
This is a two-step process usually:
Locate and load the assembly/dll:
Assembly assembly = Assembly.LoadFrom(DLL);
Instantiate the implemented class:
Type type = assembly.GetType(FullNameOfImplemented);
AppInstance = (ClassToImplement)Activator.CreateInstance(type, parameters);
The process you are looking for is often called stubbing. In this case you've chosen to encapsulate the integration functionality in a library, not web services, but the principle is the same.
The idea was that the consultant would download the repo for the implementation class and include the App as a reference.
This sounds like you've got the dependency relationship the wrong way round. If the consultant's code references your app, then your app can't reference it - it'd be a circular dependency. Instead, factor your app something more in line with the following:
App
|
|
App.Integration.Contracts
^ ^
| |
| App.Integration.Stub
|
App.Integration
The abstract class - it could just as easily be an interface in C# - resides in the Contracts assembly. This is the only compiled dependency your application has. Then at runtime use configuration to load either the stub, or the full implementation using an IoC container. An example is Unity for which you will need its configuration API. Reference the true type to use in the configuration file and change only that to update your application to use the full functionality.
First off I think you need to implement a proper plugin system if you dont want to share your code with that other developers.
Second you should code against your interface and not against its implementation. First because you dont have it and second because you may want to switch implementations for different 3rd party software.
If you need an instance for testing or stuff, you can use a handwritten mock or an mocking framework. If you need a real instance later on (when the other developers have delivered) you can use some design pattern like factory pattern or others for the creation. Try to avoid the new keyword if you want to change implementations later on.
I have two projects in my solution. One represents the main project and another one has the name of the first project but adds ".API" at the end, which acts as an assembly for my interfaces.
Since I use an interface for specific classes, I access the interface and not the actual concrete class, this brings a problem when I was to access a file from the main assembly inside a file in the main assembly and that's fine, the problem comes as I need to mention it in the interface file.
Otherwise it wouldn't be accessible as the interface file is our class in this example.
Here is a code example...
namespace App.Classes
{
public class User : IUser
{
public SomeType SomeType { get; set; }
}
}
namespace App.Classes
{
public enum SomeType
{
SpecialType,
GoldType,
SilverType,
Other
}
}
namespace App.API
{
public interface IUser
{
public SomeType SomeType { get; set; }
}
}
The error I am receiving is the type or namespace name 'SomeType' could not be found.
When trying to add
using App to the interface file I receive an error telling me that namespace doesn't exist.
Primary assembly name: App
API assembly name: App.API
If i understand you correctly,
You have referenced your API (App.API), from you main app (App).
You are then trying to call/reference SomeType in your API which actually located back in (App).
Basically this (if it could be done) is called a Circular Reference for which .Net disallows.
Further more
The type or namespace name 'SomeType' could not be found
This error is entirely appropriate, because there is no reference (even check your API project) from the App.API project to App. I know its not there because it cant be done, .Net wont let you. Ergo Circular Reference
You need to make common things common, i.e If your API needs to know about SomeType it has to be placed in your API assembly (or a more common assembly that both App and App.API can reference).
The simple solution is to put SomeType back into App.API (the project, not just the namespace)
namespace App.API.Enums
{
public enum SomeType
{
SpecialType,
GoldType,
SilverType,
Other
}
}
Or to create a 3rd assembly and reference it from both the App and App.Api projects
I know how to get all types that implement an interface such as using this code.
However I have not figured out why I can't make this work in my Asp.Net MVC ApiController. I have two projects (apologies for the naming convention. I created a solution from scratch just to make sure that my existing one was not the cause of the error):
.sln
-WebAPI
-ClassLibrary1
-Interface1
-Class1 : Interface1
WebApi has a project reference to ClassLibrary1.
Calling my ApiController it looks at the dlls in the bin directory. It is able to get ClassLibrary1.dll but when it tries to look at which type is assignable from Interface1 it does not find anything.
Code is just a .net mvc project and class library and hosted here
You don't need to find referenced assembly by its path, you can just use the type to get its assembly as below:
internal class Program
{
private static void Main(string[] args)
{
var type = typeof(Interface1);
Assembly loadedAssembly = type.Assembly;
var types = loadedAssembly.GetTypes().Where(c => type.IsAssignableFrom(c));
foreach (var typeFound in types)
{
Console.WriteLine(typeFound.Name);
}
Console.ReadKey();
}
}
Output:
Interface1
Class1
The problem is that you have the assembly ClassLibrary1 loaded twice and therefore ClassLibrary1.Interface1 from the reference is not the same interface as ClassLibrary1.Interface1 from the loaded assembly.
Move Interface1 to its own shared library and reference this shared library in both ClassLibrary1 and WebAPI to solve your problem.
About Assembly.LoadFile, this is fine if you're planning to make a plugin like system. This is not needed if you are referencing the library because then you can just enumerate the types from the already loaded assembly.
In that case you can use:
typeof(Interface1).Assembly.GetTypes().Where(c => typeof(Interface1).IsAssignableFrom(c));
as suggested by Bhushan Firake.
I have created a widows application with setup project. I compiled and build.Everything looks fine.
For changing the configuration file during installation am trying to add a new Installer file. when i add it by default i get the below code
Collapse | Copy Code
[RunInstaller(true)]
public partial class Installer : Installer
{
public Installer()
{
InitializeComponent();
}
}
When i compile this Am gettin
Circular base class dependency involving 'windows_setup.Installer' and 'windows_setup.Installer'
windows setup is the name space i used for the application. Then i found that i need to create the new classs which inbherits Installer.So i changed my class name to
public partial class MyInstaller : Installer
Now am Getting
Inconsistent accessibility: base class 'windows_setup.Installer' is less accessible than class 'windows_setup.MyInstaller'
Suggest your ideas.
Thanks
Well, you can't have a public class inheriting from an internal class for example. Try to set everything as internal if not required outside, or public otherwise.
Either change class Installer and MyInstaller to public.
Write Something like this:
System.Configuration.Install.Installer and class definition should be public partial
[RunInstaller(true)]
public partial class MyInstaller : System.Configuration.Install.Installer
{
public MyInstaller()
{
InitializeComponent();
}
}
I have a web service with the namespace as the following:
namespace MyNS
{
class MyObject
{
//Implementation here
}
}
And I published the webservice and try to consume that webservice from the next C# Website.
I assigned the service name to "MyWS".
When I try to write the code
I have to write,
MyWS.MyObject obj = new MyWS.MyObject();
But I want to write
MyWS.MyNS.MyObject obj = new MyWS.MyNS.MyObject();
The problem is there might by MyObject class under other Namespaces. So, I want to identify my classes by NameSpaces.
What should I do to use Namespace in the coding?
I do not believe the original namespace is exposed as part of the WSDL, which is what the generation process uses to create the client end point.
This means there is no way to control what namespace your web service is used as.
However you can control what namespace your client end point uses. When you add the service reference, the bottom of the first page (Titled Add Service Reference, and containing Discovery controls) is a text box titled "Namespace". If you change that field to MyWS.MyNS when adding the service it should allow you to reference it as such.
The problem is there might by MyObject class under other Namespaces. So, I want to identify my classes by NameSpaces.
The compiler will give you an ambiguous reference error if you try to use conflicting object names. You will have to qualify them in that case.
So, if you want to give it a certain alias, just type the name as you want it.
namespace This.Is.My.Favorite.Namespace
{
public class MyObject()
{
//stuff
}
}
namespace MyNS.MyWS
{
class MyObject
{
//Implementation here
}
}