Donotalo
Donotalo

Reputation: 13025

Preventing users to access class fields

I'm writing a DLL using C# 4.0 which will be used by several C# .NET based desktop applications (let's call them AppA and AppB). It is required that AppA will be able to use certain class' selected fields/properties/functions that won't be even available to AppB. My approach was to use internal modifier for those properties and grant access to AppA by specifying AppA's assembly name in InternalsVisibleTo attribute of the DLL. But internal modifier is also required in some properties which will be accessed in other parts of the DLL but not to be accessed by AppA. Now it appears that there are too many internals which are exposed to AppA which shouldn't be accessible by AppA.

In other words, consider the following properties:

class A
{
    internal int ReallyInternal {get; set;}
    internal int AppAInternal {get; set;}
}

If I use InternalsVisibleTo attribute for AppA, then both ReallyInternal and AppAInternal properties will be exposed to AppA - where as ReallyInternal shouldn't be exposed to AppA.

How to solve this? Is there any other way to implement this scenario?

Background

Before going to InternalsVisibleTo approach we thought of other ways, like having different interfaces etc. The class library I'm writing will be used by multiple applications. I wanted to have the interface same across applications.

Consider TT4 as a class in the DLL. It's properties will be populated from a physical device via serial communication.

TT4 tt4 = new TT4();
// Some code to populate tt4 object

MessageBox.Show(tt4.SerialNumber);
tt4.SerialNumber = "123";

Because tt4 object will represent a physical device, not all of its properties should be modifiable by all applications. This won't make sense and if we allow this then any application can change the serial number of the device. (Yes, SerialNumber can be written back to the device).

We've only one application (here AppA for example) which will be able to set and change the SerialNumber. Other applications shouldn't do that. It's prevented by making SerialNumber's setter as internal and granting permission to AppA by InternalsVisibleTo.

Please note that providing the library with two classes is not the solution. Say, I've implemented two classes for TT4 - TT4 (cannot write SerialNumber) and TT4Super (can write SerialNumber). When the DLL will be given to clients, they can still see TT4Super and use that.

I'm not the developer of other applications and I have no control of them.

Upvotes: 0

Views: 91

Answers (2)

JLRishe
JLRishe

Reputation: 101700

Are you mostly concerned that the designers of AppB are going to do something malicious with your DLL, or that you simply want to prevent them from doing something inadvertently? Making your members internal won't really prevent someone from doing harm via reflection if they want to.

One (admittedly not great) approach you could use is to make these members public, but prevent anyone except AppA from using them, by checking the calling assembly:

private void VerifyCaller(Assembly a)
{
    if (a == Assembly.GetExecutingAssembly()) { return; }

    var name = a.GetName();
    if(name.Name == "AppA" && name.GetPublicKey() == appAPublicKey) { return; }

    throw new InvalidOperationException("You can't access this");
}

private string _serialNumber;
public string SerialNumber
{
    get { return _serialNumber; }
    set
    {
        VerifyCaller(Assembly.GetCallingAssembly());
        _serialNumber = value;
    }
}

this should at least prevent anyone from easily using reflection to circumvent your defenses.

Upvotes: 1

PiotrWolkowski
PiotrWolkowski

Reputation: 8782

One way to do that would be to extract all the members that should be exposed to AppA to an abstract class (or a parent class in general) and make them protected internal. To access them from AppA it would have to inherit from the abstract class. For instance

public abstract class ParentA
{
    internal int ReallyInternal {get; set;}
    protected internal int AppAInternal {get; set;}
}

And AppA accesses it the following way:

internal class AinAppA : ParentA
{
    internal AinAppA()
    {
        this.AppAInternal = 1; // can access parents protected members
        // this.ReallyInternal = 2; // but pure internal members are not visible
    }
}

As a side note, InternalsVisibleTo is not meant to be an access modifier. It's main purpose is to make unit testing easier not to enable communication between production assemblies.

Upvotes: 2

Related Questions