I created a web service which can be called from a form to add new users to the system. The final service will add users to Active Directory and Exchange in the required format (please note that FirstName and LastName are required fields in the form, so they will never be null): using System.Collections.Generic;using System.Web.Services;namespace NewStarterWebService{[WebService(Namespace = http://tempuri.org/)]    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]    [System.ComponentModel.ToolboxItem(false)]    public class NewStarter : WebService    {        [WebMethod]        public void CreateNewUser(            string firstName,             string middleName,             string lastName,             string jobTitle,             string department,             string office,             string role,            string manager)        {            var newUser = new NewUser(firstName, middleName, lastName, jobTitle, department, office, role, manager);            newUser.Create();        }    }}The NewUser Class only has 1 method - Create() and a constructor: using System;using System.Collections.Generic;namespace NewStarterWebService{    public class NewUser    {        public readonly string FullName;        public readonly string FirstName;        public readonly string MiddleName;        public readonly string LastName;        public readonly string Department;        public readonly string Office;        public readonly string JobTitle;        public readonly string Role;        public readonly string Manager;        public readonly string Email;         public readonly string DotName;        public readonly string HomeDirectory;        public readonly string Initials;        public readonly Dictionary<string, string> DefaultProperties;        private const string Password = Password99;        public NewUser(            string firstName,            string middleName,            string lastName,            string jobTitle,            string department,            string office,            string role,            string manager)        {            Office = office;            Department = department;            FirstName = firstName.Trim();            MiddleName = middleName.Trim();            LastName = lastName.Trim();            JobTitle = jobTitle.Trim();            Role = role.Trim();            Manager = Ad.GetManagerDistinguishedName(manager);            FullName = ${FirstName} {LastName};            Email = ${FirstName}{LastName}@domain.com;            DotName = ${FirstName}.{LastName};            HomeDirectory = $@\\File\Home$\{DotName};            try            {                Initials = ${FirstName[0]}{MiddleName[0]}{LastName[0]};            }            catch (Exception ex) when (                ex is ArgumentOutOfRangeException ||                 ex is NullReferenceException ||                 ex is ArgumentNullException)            {                Initials = ${FirstName[0]}{LastName[0]};            }            // Set the default properties for AD            DefaultProperties = new Dictionary<string, string>            {                {userprincipalname,           Email},                {samaccountname,              DotName },                {sn,                          LastName},                {givenname,                   FirstName },                {displayname,                 FullName },                {description,                 JobTitle },                {mail,                        Email },                {homedirectory,               HomeDirectory },                {homedrive,                   H: },                {physicalDeliveryOfficeName,  Office },                {Manager,                     Manager },                {Initials,                    Initials }            };        }        public void Create()        {            Ad.CreateUser(this);            Ps.AddExchangeUser(this);        }         }}In the constructor, Manager is initialised with a call to the AD class, because the manager's DisplayName is sent through, but for my purposes I need this to be the DsitinguishedName. The Create() method makes a call to Ad (Active Directory) and Ps (PowerShell) to do the AD and Exchange creation. I didn't post this code because I thought that it would maybe be a bit much but if people think it would help to put the rest of it in context I will add it!
Automating New User Creation With C# Web Service
c#;web services;active directory
I would not put dependency on singleton in this class  it means two responsibility for NewUser - format properties and orchestrate AD API. Lets define this helper class to be more explicit on your validation scenarios:static class Trimming{    public static string TrimRequired(this string value, [CallerMemberName] string property = )    {        if(string.IsNullOrWhiteSpace(value))            throw new InvalidOperationException($Mailformed property {property}.);        return value.Trim();    }    public static string TrimOptional(this string value)    {        if (value == null)            return null;        return value.Trim();    }}And define UserBuilder (It makes sense to prefer properties over ctor parameters when we have so many):public class UserBuilder{    public string FirstName { get; set; }    public string MiddleName { get; set; }    public string LastName { get; set; }    public string JobTitle { get; set; }    public string Department { get; set; }    public string Office { get; set; }    public string Role { get; set; }    public string Manager { get; set; }    public IDictionary<string, string> ToProperties() =>        new Dictionary<string, string>        {            {userprincipalname, RequiredEmail},            {samaccountname, RequiredDotName },            {sn, RequiredLastName},            {givenname, RequiredFirstName },            {displayname, RequiredFullName },            {description, OptionalJobTitle },            {mail, RequiredEmail },            {homedirectory, RequiredHomeDirectory },            {homedrive, H: },            {physicalDeliveryOfficeName, OptionalOffice },            {Manager, RequiredManager },            {Initials, RequiredInitials }        };    string RequiredFullName => ${RequiredFirstName} {RequiredLastName};    string RequiredEmail => ${RequiredFirstName}{RequiredLastName}@domain.com;    string RequiredDotName => ${RequiredFirstName}.{RequiredLastName};    string RequiredHomeDirectory => $@\\File\Home$\{RequiredDotName};    string RequiredInitials    {        get        {            try            {                return ${RequiredFirstName[0]}{OptionalMiddleName[0]}{RequiredLastName[0]};            }            catch (Exception ex) when (                ex is ArgumentOutOfRangeException ||                ex is NullReferenceException ||                ex is ArgumentNullException)            {                return ${RequiredFirstName[0]}{RequiredLastName[0]};            }        }    }    string OptionalOffice => Office.TrimOptional();    string OptionalDepartment => Department.TrimOptional();    string RequiredFirstName => FirstName.TrimRequired();    string OptionalMiddleName => MiddleName.TrimOptional();    string RequiredLastName => LastName.TrimRequired();    string OptionalJobTitle => JobTitle.TrimOptional();    string RequiredRole => Role.TrimRequired();    string RequiredManager => Manager.TrimRequired();}P.S. Generally speaking, it makes sense to do not hold an intermediate state of you calculations (like trimmed string values)  just an original data + define functions/properties to process them. It makes your design more flexible.P.P.S. It might be useful to have UserName class:   class UserName   {        public string FirstName { get; set; }        public string MiddleName { get; set; }        public string LastName { get; set; }        public string FullName => ...        public string Initials => ...   }... and use in UserBuilder. 