2010-06-29 18 views
9

Sto iniziando un nuovo progetto con Mongo, NoRM e MVC .Net.Come passare ObjectId da MongoDB in MVC.net

Prima di utilizzare FluentNHibernate in modo che i miei ID fossero interi, ora i miei ID sono ObjectId. Così, quando ho un link Modifica il mio URL simile a questo:

WebSite/Amministratore/Modifica/23,111,160,3,240,200,191,56,25,0,0,0

E non si lega automaticly al mio controller come un ObjectId

Avete suggerimenti/buone pratiche per lavorare con questo? Devo codificare/decodificare l'ID ogni volta?

Grazie!

risposta

14

Io uso seguente

public class ObjectIdModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     string value = controllerContext.RouteData.Values[bindingContext.ModelName] as string; 
     if (String.IsNullOrEmpty(value)) { 
      return ObjectId.Empty; 
     } 
     return new ObjectId(value); 
    } 
} 

e

protected void Application_Start() 
    { 
     ...... 

     ModelBinders.Binders.Add(typeof(ObjectId), new ObjectIdModelBinder()); 
    } 

quasi dimenticato, rendere gli URL da ObjectId.ToString()

+1

Questa soluzione non funziona quando i valori vengono passati in un modulo. Vedi la mia risposta per una soluzione che funziona indipendentemente da come vengono passati i valori. (Potrebbe anche valere la pena di notare quale driver C# MongoDB è stato utilizzato poiché la loro sintassi varia). –

+0

La domanda originale era nel contesto ASP.NET MVC e codice standard che consentirebbe al controllore di analizzare ObjectId dall'URL. – Sherlock

0

non ho familiarità con il tipo ObjectId ma si poteva scrivere un custom model binder che si prenderà cura di convertire il vincolo id percorso a un'istanza di ObjectId.

0

Sapevi che puoi utilizzare l'attributo [MongoIdentifier] per far sì che qualsiasi proprietà agisca come chiave univoca?

Ho risolto questo problema prendendo in prestito una tecnica da WordPress facendo in modo che ogni entità fosse anche rappresentata da una proprietà "url slug" e decorando tale proprietà con [MongoIdentifier].

Quindi, se avessi una persona di nome Johnny Walker, creerei una frase di "johnny-walker". Devi solo assicurarti che questi sll di URL rimangano univoci e puoi mantenere gli URL puliti senza brutti ID di oggetto.

+0

Yup che conosco che, dal momento che è solo per il amministrazione Non ho bisogno di avere URL puliti. Per ora, ho aggiunto una proprietà IdValue che esegue il rendering del valore ObjectId come stringa e quando ho bisogno di recuperare i dati, faccio semplicemente .Single (nuovo ObjectId (id)) non sono sicuro che sia il modo migliore ma funziona correttamente ... – VinnyG

13

Utilizzare un modello personalizzato legante come questo ... (lavora contro il ufficiale C# MongoDB driver)

protected void Application_Start() 
{ 
    ... 
    ModelBinders.Binders.Add(typeof(ObjectId), new ObjectIdModelBinder()); 
} 

public class ObjectIdModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     var result = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
     if (result == null) 
     { 
      return ObjectId.Empty; 
     } 
     return ObjectId.Parse((string)result.ConvertTo(typeof(string))); 
    } 
} 
+0

Genera un'eccezione quando il parametro viene manipolato. Penso che usare TryParse e restituire ObjectId.Empty quando non è valido è un modo migliore di gestirlo. – phloopy

0

Per API Web è possibile aggiungere dei parametri personalizzati ULE vincolante WebApiConfig:

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     //... 
     config.ParameterBindingRules.Insert(0, GetCustomParameterBinding); 
     //... 
    } 

    public static HttpParameterBinding GetCustomParameterBinding(HttpParameterDescriptor descriptor) 
    { 
     if (descriptor.ParameterType == typeof(ObjectId)) 
     { 
      return new ObjectIdParameterBinding(descriptor); 
     } 
     // any other types, let the default parameter binding handle 
     return null; 
    } 

    public class ObjectIdParameterBinding : HttpParameterBinding 
    { 
     public ObjectIdParameterBinding(HttpParameterDescriptor desc) 
      : base(desc) 
     { 
     } 

     public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) 
     { 
      try 
      { 
       SetValue(actionContext, new ObjectId(actionContext.ControllerContext.RouteData.Values[Descriptor.ParameterName] as string)); 
       return Task.CompletedTask; 
      } 
      catch (FormatException) 
      { 
       throw new BadRequestException("Invalid ObjectId format"); 
      } 
     } 
    } 
} 

e utilizzarlo senza alcun attributi aggiuntivi nel controllore:

[Route("{id}")] 
public IHttpActionResult Get(ObjectId id) 
Problemi correlati