Configurare il mio modello di ereditarietà?

1

Sto lavorando al refactoring di un'app Web di sincronizzazione utilizzata dalla nostra azienda. Attualmente è semplicemente un insieme di controller che attivano una serie di helper che attraversano una lunga catena di istruzioni di tipo if-else.

Sto tentando di creare un wrapper attorno al riferimento web SalesForce Soap, ma sto riscontrando qualche problema con un buon modello di ereditarietà.

Quando si usa il wrapper, voglio essenzialmente poter dire qualcosa del tipo

var SalesForce = new SalesForceApi(Username, Password, Url);
var tmp1 = SalesForce.Users.GetUsers();
// or
var tmp2 = SalesForce.Users.GetUserById(id);
// or
var tmp3 = SalesForce.Organizations.GetOrganizations();
// you get the picture.

Idealmente vorrei creare un'istanza dell'oggetto SalesForceApi, e semplicemente passare la sua connessione attiva attraverso tutte le sue diverse richieste e tipi di richieste. Sono solo un po 'confuso sulla porzione di implementazione.

Penso di essere in qualche modo nella giusta direzione.

Ho creato una classe astratta chiamata Base che contiene un oggetto chiamato Binding con il tipo SforceService . Contiene metodi di accesso e disconnessione utilizzati per creare una connessione attiva. Quando viene creato un oggetto SalesForceApi con nome utente, password e url, questi vengono passati alle sottoclassi come Users che ereditano la classe Base . Questi valori vengono quindi passati alla classe Base per creare un oggetto vincolante attivo.

Modifica

Ecco alcune lezioni che ho creato che mi danno un po 'di un metodo per realizzare ciò che voglio.

La mia Main SalesForce class (o SalesForceApi)

namespace SyncTool.Core.Services.SalesForce
{
    public interface ISalesForce
    {
        IAccounts Accounts { get; }
        IAttachments Attachments { get; }
        ICases Cases { get; }
        IContacts Contacts { get; }
        IGroups Groups { get; }
        IRecordTypes RecordTypes { get; }
        IUsers Users { get; }    
    }

    public class SalesForceApi:ISalesForce
    {
        public IAccounts Accounts { get; set; }
        public IAttachments Attachments { get; set; }
        public ICases Cases { get; set; }
        public IContacts Contacts { get; set; }
        public IGroups Groups { get; set; }
        public IRecordTypes RecordTypes { get; set; }
        public IUsers Users { get; set; }

        public SalesForceApi()
        {
            Accounts = new Accounts();
            Attachments = new Attachments();
            Cases = new Cases();
            Contacts = new Contacts();
            Groups = new Groups();
            RecordTypes = new RecordTypes();
            Users = new Users();
        }
    }
}

La classe Base richiesta

namespace SyncTool.Core.Services.SalesForce.Requests
{
    public abstract class RequestBase: IDisposable
    {
        private const string User = "[email protected]";
        private const string Pass = "foobar";
        private const string Url = "url";

        public SforceService Binding;
        public Logger Logger = LogManager.GetCurrentClassLogger();

        protected RequestBase()
        {
            Login(User, Pass, Url);
        }

        public bool Login(string username, string password, string url)
        {
            Binding = new SforceService { Url = url, Timeout = 60000 };
            LoginResult lr;

            try
            {
                lr = Binding.login(username, password);
            }
            catch (SoapException e)
            {
                Logger.Error("An error has occurred",e);
                return false;
            }

            Binding.SessionHeaderValue = new SessionHeader { sessionId = lr.sessionId };
            Binding.Url = lr.serverUrl; 
            return true;
        }

        public bool Logout()
        {
            try
            {
                Binding.logout();
                return true;
            }
            catch (SoapException)
            {
                return false;
            }
        }

        public void Dispose()
        {
            Logout();
            Binding.Dispose();
        }
    }
}

Ed ecco un esempio di una delle classi di richieste

namespace SyncTool.Core.Services.SalesForce.Requests
{
    public interface IUsers
    {
        List<User> GetUsers();
        User GetUserById(string id);
        List<User> GetUsersByEmail(string email);
        User GetUserByEmail(string email);
    }

    public class Users : RequestBase, IUsers 
    {
        public List<User> GetUsers()
        {
            try
            {
                const string soqlQuery = "SELECT Id, Name, FirstName, LastName, Email FROM User";
                var qResult = Binding.query(soqlQuery);
                var done = false;
                if (qResult.size <= 0) return new List<User>();
                var users = new List<User>();
                while (!done)
                {
                    var records = (qResult.records.Cast<User>().ToList());
                    users.AddRange(records);
                    if (qResult.done)
                        done = true;
                    else
                        qResult = Binding.queryMore(qResult.queryLocator);
                }
                return users;
            }
            catch (SoapException e)
            {
                Logger.ErrorException("An unexpected error occurred when retreiving users.",e);
                return null;
            }
        }

        public User GetUserById(string id)
        {
            try
            {
                var qResult = Binding.query("SELECT Id, Name, FirstName, LastName, Email FROM User WHERE Id='" + id + "'");
                if (qResult.size <= 0) return new User(); 
                var records = (qResult.records.Cast<User>().ToList());

                return records.Count > 0 ? records.FirstOrDefault() : new User();
            }
            catch (SoapException e)
            {
                Logger.ErrorException("An unexpected error occurred when retreiving users.", e);
                return null;
            }
        }

        public List<User> GetUsersByEmail(string email)
        {
            try
            {
                var qResult = Binding.query("SELECT Id, Name, FirstName, LastName, Email FROM User WHERE Email='" + email + "'");
                if (qResult.size <= 0) return new List<User>();
                var records = (qResult.records.Cast<User>().ToList());

                return records;
            }
            catch (SoapException e)
            {
                Logger.ErrorException("An unexpected error occurred when retreiving users.", e);
                return null;
            }
        }

        public User GetUserByEmail(string email)
        {
            try
            {
                var qResult = Binding.query("SELECT Id, Name, FirstName, LastName, Email FROM User WHERE Email='" + email + "'");
                if (qResult.size <= 0) return new User();
                var records = (qResult.records.Cast<User>().ToList());

                return records.Count > 0 ? records.FirstOrDefault() : new User();
            }
            catch (SoapException e)
            {
                Logger.ErrorException("An unexpected error occurred when retreiving users.", e);
                return null;
            }
        }
    }
}
    
posta JD Davis 03.12.2015 - 20:27
fonte

1 risposta

1

I'm attempting to build a wrapper around the SalesForce Soap web reference

Non vedo nulla in quello che mostri che arriva a confezionare un oggetto SOAP. Ma per favore, sopportami mentre passo attraverso quello che vedo ...

When using the wrapper, I want to essentially be able to say something like ...

Io chiamo questo "design del pensiero pio". Progetta le cose come vuoi che siano. Quindi avvolgere o manipolare l'oggetto di destinazione esistente in modo che possiamo usarlo nel modo che vogliamo.

Disegna le classi che supportano ciò che desideri. Finora vedo:

  • Classe SalseForceApi, contenente
    • Raccolta utenti
    • Raccolta di organizzazioni
    • Nome utente, password, URL
      • Ancora nessuna idea se queste sono proprietà separate o contenute in 1 o più altre classi
    • Oggetto SforceService
  • Classe utente
  • Classe raccolta utenti
    • GetUserById
    • getusers
  • Classe di organizzazione
  • Classe di raccolta organizzazione
    • GetOrganizations
  • Classe SforceService
    • Accedi
    • Esci

Base (classe astratta)

nome pessimo.

... Users which inherit the Base class.

Questo sembra essere solo un altro problema nel design generale, ma sembra che il "modello di ereditarietà" sia la questione centrale. Ciò sembra suggerire che User contenga un oggetto di riferimento SOAP spostato.

Non vedo l'ereditarietà come soluzione. Certo, sono profondamente ignorante del tuo spazio problematico, ma l'ignoranza è beatitudine. Quindi eccoci ...

sForceService

Lo vedo come l'involucro di cui parli. E stiamo fondamentalmente parlando dell'idea del modello dell'adattatore qui.

Il wrapper racchiude tutto il lavoro per creare e usare l'oggetto soap. Espone ciò che contiene l'oggetto soap.

'SalesForceApi' passa attraverso quella "Sales Force API".

Composizione dell'adapter

public class sForceService {
    public sForceService ( User theUser, ??? url ) {
         // in here set up with stuff provided by theUser
   }

   // the adapter makes the connection, fetches stuff and exposes same
   // through public methods...
}


public class SalesForceApi {
    protected sForceService SFS { get; set; }

    // Maybe the api class constructor, in part, might looks a little like this
    public SalseForceApi ( string userName, string password, ??? url ) {
        User someOne = new User(userName, password);
        sForceService SFS = new sForceService ( someOne, url);
    }

    public User User(int id) {
        return SFS.User(id);
    }

    public UserCollection Users {
        get { return SFS.Users(); }
    }

    public OrganizationCollection Organizations {
        { get SFS.Organizations(); }
    }

    public OrganizationCollection UserOrganizations (User forThisGuy) { }
}


//CLIENT code
SalesForceApi sfa = new SalesForceApi ( someUser, someURL );
var tmp1 = sfa.User(34);
var tmp2 = sfa.Users;
var tmp3 = sfa.Organizations;
var tmp4 = sfa.UserOrganizations( fred );
    
risposta data 03.12.2015 - 23:38
fonte