Akusas
Akusas

Reputation: 529

Populating a Dictionary from a Class using Reflection

I want to use a dictionary to replace words in a HTML template between two $ signs. I've got it working when I add the keys myself, but I want to be able to replace using reflection, so that if I give this project to someone else, then they only need to change the class and the template keys.

I've got the Class with some properties. I populate this class and then try to populate the dictionary.

public class FeedMessageValue
{
    public string Username { get; set; }
    public string SubscriptionID { get; set; }
    public DateTime MessageTime { get; set; }
}

public class FeedMessageData : IMailData
{
    private FeedMessageValue feedMessageValue;

    public FeedMessageData(string username, string subscriptionID, DateTime messageTime)
    {
        this.feedMessageValue = new FeedMessageValue
        {
             Username = username
           , SubscriptionID = subscriptionID
           , MessageTime = messageTime
        };

    PropertyInfo[] infos = this.feedMessageValue.GetType().GetProperties();
    foreach (PropertyInfo info in infos)
    {
        this.getMergeValues().Add(info.Name, info.GetValue(this.feedMessageValue, null).ToString());
    }
}

public Dictionary<string, string> getMergeValues()
    {
        return new Dictionary<string, string>();
    }
}

This runs through the Email Generator:

public interface IMailData
    {
        Dictionary<string, string> getMergeValues();
    }

    public interface IEmailGenerator
    {
        MailMessage generateEmail(IMailData mailData, string htmlTemplate, string textTemplate);
    }

    public class EmailGenerator : IEmailGenerator, IRegisterInIoC
    {
    // Setup the rules 
    static readonly Regex emailRegex = new Regex(@"\$([\w\-\,\.]+)\$", RegexOptions.Compiled);

    private string mergeTemplate(string template, IReadOnlyDictionary<string, string> values)
    {
        string emailTextData = emailRegex.Replace(template, match => values[match.Groups[1].Value]);
        return emailTextData;
    }

    public MailMessage generateEmail(IMailData mailData, string htmlTemplate, string textTemplate)
    {
        // MailMessage
    }
}

So, in theory one of the dictionary keyvalue pairs should now be {"Username", username}, but using my code to replace for $Username$, then it throws a bug with that there is no key for Username.

Upvotes: 1

Views: 913

Answers (1)

Joshua Robinson
Joshua Robinson

Reputation: 3539

The problem is with getMergeValues(). You're creating a new instance of Dictinary<string, string> each time. Change that method to a property, or have it return a field.

As it is right now, when you're looping through the PropertyInfo[], you create a new instance of Dictionary<string, string>, add { "Username", username }, then don't do anything with the reference to the Dictionary<string, string> you created. Then on the next iteration of the loop you create a second Dictionary<string, string> this one with, perhaps, { SubscriptionId, subscriptionID }, and don't do anything with the reference. And so on and so on.

public class FeedMessageData : IMailData
{
    private FeedMessageValue feedMessageValue;

    public FeedMessageData(string username, string subscriptionID, DateTime messageTime)
    {
        MergeData = new Dictionary<string, string>();
        this.feedMessageValue = new FeedMessageValue
        {
             Username = username
           , SubscriptionID = subscriptionID
           , MessageTime = messageTime
        };

        PropertyInfo[] infos = this.feedMessageValue.GetType().GetProperties();
        foreach (PropertyInfo info in infos)
        {
            MergeData.Add(info.Name, info.GetValue(this.feedMessageValue, null).ToString());
        }
    }

    public Dictionary<string, string> MergeData { get; }
}

Upvotes: 1

Related Questions