Matt Mills
Matt Mills

Reputation: 8792

Can I hide sensitive property values from a c# 9 record's autogenerated methods?

I'm building a user management system, with a domain host to which I am sending commands. The commands are records both because of the init-only properties and because of the generated helper methods. However, I quickly ran into a problem with this approach for e.g. the LoginUserCommand.

command.ToString() returns something like this (formatting added):

LoginUserCommand { 
    Identity = 10000000-1111-2222-3333-444444444444,
    CorrelationId = 20000000-1111-2222-3333-444444444444,
    Timestamp = 2013-07-26T16:45:20Z,
    IssuingUserId = 30000000-1111-2222-3333-444444444444,
    EntityId = a80c081c-cf91-4304-9baa-20fb20c8d9f7,
    IPAddress = 127.0.0.1,
    Password = ThisIsAPr0blem
}

Obviously I can work around this by e.g. overriding ToString() on the classes where it matters. Naïvely, I might do something like

public override string ToString()
{
    return base.ToString()
        .Replace(Password, "********");
}

But I'm wondering whether I've overlooked some built-in way to have the generated ToString() method mask the value of the Password property.

Upvotes: 13

Views: 1939

Answers (2)

OwnageIsMagic
OwnageIsMagic

Reputation: 2299

You can isolate sensitive properties in derived class and override PrintMembers.

var s = new Entity("ss11", 99, "supersecret");
Console.WriteLine(s);
Console.WriteLine(s.secret);
// Output:
// EntityWithSecret { s1 = ss11, i2 = 99 }
// supersecret

public record EntityNoSecret(string s1, int i2);
public record Entity(string s1, int i2, string secret) : EntityNoSecret(s1, i2)
{
    protected override bool PrintMembers(StringBuilder builder)
        => base.PrintMembers(builder);
};

Upvotes: 2

mausworks
mausworks

Reputation: 1625

You can remap your record with the with syntax and use PrintMembers instead, which I think is cleaner:

public override string ToString()
{
    var builder = new StringBuilder();
    
    (this with { Password = null }).PrintMembers(builder);

    return builder.ToString();
}

There have also been proposals for introducing an attribute such as [PrintMembersIgnore] for records, but nothing like it has been implemented. It can however be solved with code generation, which was the method suggested by the dotnet team (see comment in the thread), a project for this has been started.

Upvotes: 18

Related Questions