Pattern accettati per la classe base con origini dati statiche e definite dall'utente

1

Ho l'obbligo di creare una libreria di profili "di base" (in C # - NET 4.5.2) per vari consumatori interni (tecnici). Questo profilo consiste di campi di metadati che sarebbero condivisi da un'ampia varietà di implementazioni di profili differenti. I metadati per questi diversi profili sono archiviati in una singola posizione, ma ogni effettiva implementazione per il profilo di base avrà la propria memoria di dati (di cui non saprò nulla).

Invece di fornire un servizio effettivo, forniremo solo le classi / interfacce di base necessarie per consentire agli sviluppatori di implementare i propri servizi di profilo.

Idealmente, mi piacerebbe rendere l'idratazione dei campi di metadati del profilo di base completamente automatica per gli sviluppatori, che si concentrano sull'idratazione dei loro campi solo nella loro classe figlia.

I miei requisiti sono:

  • Profilo di base tutti gli altri oggetti profilo devono ereditare
  • Il profilo di base si autoidrata da un'origine dati statica che è opaca per gli implementatori.
  • La possibilità di eseguire query per molti profili in base a un predicato, un elenco di ID profilo o entrambi.
  • Operazioni CRUD per un determinato profilo che consentono dette operazioni sui metadati del profilo di base oltre a qualsiasi cosa l'utente debba eseguire nei propri sistemi.

L'idea che è stata già lanciata include la possibilità per gli sviluppatori di fornire una funzione generatore ( Func<Guid, Profile<T>> ) in cui Guid è l'Id del profilo (per le letture esistenti) e la funzione esegue qualsiasi logica richiesta dallo sviluppatore per inizializzare il profilo mentre allo stesso tempo ottenere i dati del profilo di base.

Sarei curioso di sentire le opinioni della comunità su questo però (e anche se questo è anche un buon corso da tracciare).

    
posta PremiumTier 29.07.2015 - 18:41
fonte

1 risposta

1

Recentemente ho realizzato un'implementazione del framework Identity di ASP.NET 5 che era un problema nel calcio, ha il suo UserStore (e RoleStore ) che è un po 'fastidioso da implementare.

La mia implementazione può essere trovata qui , potrebbe darti qualche idea!

Questo suona sorta di come la stessa cosa. È necessario un base class in cui è possibile memorizzare diversi tipi di profili (?), Ma solo metodi astratti per ottenere / impostare questi profili. Mi piace il modello che fornisce le classi di base di Identity, anche se è un po 'fastidioso da implementare, perché offre all'installer piena libertà di quali data-store (s) vuole usare.

Da quello che posso dire dalla tua domanda, ogni profilo deve avere un ID che deve essere un System.Guid .

Quindi, perché non iniziare con un'interfaccia contenente solo questo?

public interface IProfile
{
    Guid Id { get; }
}

Allora perché non implementare Store per IProfile , come in Identità

public abstract class ProfileStore<TProfile>
    where TProfile : class, IProfile
{
    public abstract Task<TProfile> FindByIdAsync(Guid profileId);
    public abstract Task<IEnumerable<TProfile>> FindManyAsync(Expression<Func<TProfile, bool>> query);
    public abstract Task SaveProfileAsync(TProfile profile);
}

Potresti (ovviamente) voler aggiungere altri metodi per ottenere o salvare i tuoi profili.

Tutti i negozi di profili possono quindi essere aggiunti a una sorta di ProfileStoreCollection in cui è possibile auto-idratare tutti i negozi eseguendo il iterazione su di essi e richiamando il metodo InsertAsync.

Questo dovrebbe essere sufficiente per quello che stai chiedendo, per favore commenta se ho perso parte vitale!

Ecco un esempio di implementazione (usando MongoDB e il suo ultimo driver):

Un profilo:

public class SomeProfile : IProfile
{
    [BsonId]
    public Guid Id { get; set; }

    public string Name { get; set; }

    public DateTime Expires { get; set; }
}

Il negozio:

public class MongoDBProfileStore : ProfileStore<SomeProfile>
{
    private IMongoCollection<SomeProfile> _profileCollection;

    public MongoDBProfileStore(IMongoCollection<SomeProfile> profileCollection)
    {
        _profileCollection = profileCollection;
    }

    public override async Task<SomeProfile> FindByIdAsync(Guid profileId)
    {
        var filter = Builders<SomeProfile>.Filter
            .Eq(nameof(SomeProfile.Id), profileId);
        // the nameof-keyword is new in C#6 (returns "Id")

        var profiles = await _profileCollection.FindAsync(filter);
        await profiles.MoveNextAsync();

        if (profiles.Current != null)
        {
            return profiles.Current.FirstOrDefault();
        }
        return null;
    }

    public override async Task<IEnumerable<SomeProfile>> FindManyAsync(Expression<Func<SomeProfile, bool>> query)
    {
        var profiles = await _profileCollection.FindAsync(query);

        await profiles.MoveNextAsync();

        if (profiles.Current != null)
        {
            return profiles.Current.ToList();
        }
        return null;
    }

    public override async Task SaveProfileAsync(SomeProfile profile)
    {
        await _profileCollection.InsertOneAsync(profile);
    }
}
    
risposta data 02.08.2015 - 18:21
fonte

Leggi altre domande sui tag