I have a game client written in Unity and a Server written in Azure Functions. I have a class library in the Azure Function solution with "Domain" classes that will be shared between both client and server.
I build the class library to a DLL and drop it in a Plugins folder in Unity, so I can use the shared code in the game client.
This works well, but I came across a situation where I need the game client to have special properties that I don't want the server to have in its solution because it just adds complexity and dependencies (such as dependencies on the Unity Game engine for example that have no business in the server).
What's the cleanest way to make a class that can be enhanced in the game client but kept basic in the server?
Option 1:
use inheritance
public class DomainGun
{
public int BulletCount;
public string Name;
public DomainBullets Bullets;
}
public class DomainBullets
{
public string Property;
}
public class GameClientBullet: DomainBullets
{
BulletRendere Renderer;
}
This fails, because now I have to downcast from DomainBullets to GameClientBulletto get to the Renderer when I do things with the DomainGun on the client.
I can probably do it with generics.
public class DomainGun
{
public int BulletCount;
public string Name;
public DomainBullets Bullets;
}
public class DomainBullets<T>
{
public string Property;
public T Renderer;
}
//now I can do this on the server:
public interface IBulletRenderer
{
//placeholder that has nothing in it
}
//and this on the client..
public class BulletRenderer
{
UnityRenderingThing UnityDependentThing;
}
I think this will work - allows me to have shared properties in one place, and then have the client make it more specialized, but using generics in this way with an empty interface feels like a code smell.
I think there is a more clever way to do this with interfaces, but I am spacing right now.
Appreciate any ideas.
Use the decorator design pattern. Keep the base class on the server and the decorator on the client.
https://www.dofactory.com/net/decorator-design-pattern
Related
I've got a Blazor WebAssembly project with an ASP.NET WebAPI hosted service. If I use the auto-generated code in the "Connected Services" in Visual Studio to retrieve the OpenAPI definition, I get a nice proxy representing all of the HTTP endpoints, complete with request and reply objects.
But the generated request/reply classes have only a default constructor and properties, like:
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.0.22.0 (Newtonsoft.Json v11.0.0.0)")]
public partial class GetDetailedMessageRequest
{
[Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public long Id { get; set; }
}
I prefer to have at least the option of a constructor with each of the properties - this is actually the way the classes are in the service side:
public class GetDetailedMessageRequest
{
public GetDetailedMessageRequest() { }
public GetDetailedMessageRequest(long id)
{
ID = id;
}
public long ID { get; set; }
}
Is there any way to either have the code generator build these constructors, or tell it not to create the model classes at all, and instead let both the client reference the shared models project?
Neither of these seems likely - I can think of a couple workarounds, like manually editing the generated code, or creating the request on the client using the class from my shared project, serializing it, deserializing it into the generated class type, or possibly just building the constructors again in new partial classes for all of these...But obviously those are not ideal.
I could always build my own code generator, or skip the generated stuff altogether and just use HttpClient normally - but I like the idea of an auto-generated proxy class.
I am trying to create tools for a game to learn, as well as improve my own playing experience.
The primary .NET assembly, csass.dll, that controls the client is heavily obfuscated, and I have no control over this .dll-file at all and reading it's code is very time consuming. The game also includes a mainapi.dll which handles the communication between server and client. I have full control over this assembly and I can listen to the servers responses and send my own requests, which already gives me some pretty nice functionality, however there are some limitations I'd like to work around.
csass.dll references mainapi.dll, by default mainapi does not reference csass. In csass.dll there is a class, let's call it clickHandler, that has a public, non-static method ClickObj() of return type void. I want to call this method from within mainapi.dll, but I have no idea how to go about this, given that I have to leave csass.dll untouched.
Are there any feasible ways to 'retrieve' a clickHandler object (to then call its ClickObj() method) from within the mainapi assembly, without making any changes in csass.dll? Appreciate any and all input!
Create an interface:
public interface IClickHandler
{
void ClickObject();
}
Now create a helper class implementing that interface:
using CsAss;
public class ObjectClicker : IClickHandler
{
CsAss _csass;
public ObjectClicker(CsAss csass)
{
_csass = csass;
}
public void ClickObject()
{
_csass.clickObject();
}
}
Add a dependency on an instance of the interface into your MainAPI class:
public class MainApi
{
IClickHandler _clickHandler;
public MainApi(IClickHandler clickHandler)
{
_clickHandler = clickHandler;
// Now you have a class that can call the click handler for you
}
}
Now wire it all up:
public void StartupMethod()
{
var csass = new CsAss();
IClickHandler clickHandler = new ObjectClicker(csass);
var main = new MainApi(clickHandler);
// TODO: Start your app now that MainApi is properly configured
}
That last step is the only potentially tricky part, depending on your project layout. You need something that can create an instance of CsAss, MainApi and ObjectClicker. Normally I would solve that with the dependency injection (DI) pattern, either using a framework such as Autofac or so-called "poor man's DI" by manually instantiating from a central startup method. That gets a little more difficult with Unity since there isn't an easily accessible startup point. You could start looking into https://github.com/svermeulen/Zenject and go from there for options.
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.
Okay so I'm trying to create an class library for an existing game.
I'm stuck with a problem though I'd like to clear up and have done properly.
So let's say I've got my Class library in the namespace Api
This api contains multiple classes for example: Memory, Client, Player, Keyboard
Now I don't want the person using this Api to have to initialize everything personally.
I came up with the solution to use an extra class containing the initialized instances for the other classes so the user can do the following
using Api
Api.API MyGame = new Api.API();
And then having the API class be something like this:
public class API {
public Player player;
public Client client;
public API(){
Player = new Player();
Client = new Client();
}
}
I'm wondering if this is a correct way of doing or if I'm totally in the wrong here.
Take a look at using Dependecy Injection / Inversion of Control:
Autofac for registering (there are several others, such as Ninject, etc)
Managed Extensibility Framework for assembly discovery (using export and imports)
I have the following interfaces and classes:
public interface ILoggingService { ... }
public class LoggingService {
public LoggingService(ILoggingRepository loggingRepository) { ... }
...
}
public interface ILoggingRepository { ... }
public class DatabaseLoggingRepository {
public DatabaseLoggingRepository(string ConnectionString) { ... }
...
}
public class FileLoggingRepository {
public FileLoggingRepository(string LogFilePath) { ... }
...
}
I'm refactoring my software to use Unity IoC framework and am looking for a way to pass the specific configuration to each ILoggingRepository implementation.
I think that the best way would be to change DatabaseLoggingRepository's and FileLoggingRepository's constructors to have no parameters at all and have them configured by some configuration file. However, because of my acceptance tests I would need a easy way to override these settings while running my tests.
Am I on the right track and if I am, which configuration files should I use? Alternative ways are welcome as well.
What we've decided to do is create a class, in your case it would be LoggingConfiguration, and have that passed to the constructo of the repository. If you resolve using Unity it will instantiate this class using Activator, wuthout having to register it. In your tests however, you just greate a new instance of a derived configuration class, providing different values.
Does it makes sense? Should I clarify more?
Update: I've decided to provide some additional clarification. So, you already have two implementations, and now you want each configuration to query for its proper configuration setting.
I would extend the ILoggingRepository's constructor to look like this:
public ILoggingRepository(ILoggingConfigurationProvider confProvider);
You can then create one implementation for your normal operation which has two properties:
public LoggingConfigurationProvider : ILoggingConfigurationProvider {
public LoggingConfigurationProvider() {
// load both values from configuration file
}
public string LogPath { get; set; }
public string ConnectionString { get; set; }
}
When you instantiate your class via normal IoC operation this will get resolved by the container and you'll configuration options will get loaded from the conf file. When you however want to do Unit tests you:
1) Create a new "Mock" implementation
public class MockLoggingConfigurationProvider : ILoggingConfigurationProvider {
public MockLoggingConfigurationProvider() {
// set both values to a test value
}
public string LogPath { get; set; }
public string ConnectionString { get; set; }
}
Now you can either create the repository using a constructor:
new LoggingRepository(new MockLoggingConfigurationProvider());
or if you want the whole IoC mechanism to be used, you simply (when setting up the container) register this implementation of the interface. Because the unit tests are separate, you don't share the registrations right? So that should give you what you need, the ability to change this settings depending on weather they are being executed as a unit test or not.
In real life, I wouldn't even bother with this, and just create a mock logging repository and have it write somewhere else. Unless you want to test the repository to a test database/file. In which case I'd do as specified.
Hope it helps.
As a design suggestion does not force IoC to deal with configuration stuff. Each logger should manage the configuration the way they prefer in its implementation. IoC should just inject the logger. For the unit/integration test, in both case you should e able to provide a configuration for the logger, for example using log4net I'm used to configure the logging subsystem in the Startup of the test by the api, and I create an appender that write just everithing on the console. You can't Insolate configuration by IoC since each possible logging system does not necessary share a contract for the Configuration part.