2012-12-20 31 views
6

Tôi là một mô hình, với một số thuộc tính lồng nhau, danh sách ... và tôi muốn lấy tham số chuỗi truy vấn từ mô hình đó.Làm thế nào để tạo chuỗi truy vấn từ mô hình với khung asp.net mvc

Có lớp học/người trợ giúp nào trong khuôn khổ asp.net mvc để thực hiện việc này không?

Tôi biết rằng với trình kết nối mô hình, chúng tôi có thể ràng buộc một mô hình từ một chuỗi truy vấn, nhưng tôi muốn làm ngược lại.

Cảm ơn.

+0

Dưới đây là một ý tưởng: http://stackoverflow.com/questions/829080/how-to-build -a-query-string-cho-a-url-in-c –

+0

Bạn đang xây dựng toàn bộ URL hay chỉ là chuỗi truy vấn? –

+0

Tôi muốn xây dựng một chuỗi truy vấn từ một cá thể mô hình có thể được sử dụng sau với một ModelBinder. model => Property1 = 123 & Property2 = Kiểm tra & Tìm kiếm [0] Tên = Xin chào & Tìm kiếm [1] .Name = Một số khác –

Trả lời

4

Tôi khá chắc chắn không có chức năng "tuần tự hóa chuỗi truy vấn" trong khung, chủ yếu là vì tôi không nghĩ có cách tiêu chuẩn để thể hiện giá trị lồng nhau và tập hợp lồng nhau trong chuỗi truy vấn.

Tôi nghĩ điều này sẽ khá dễ dàng khi sử dụng hạ tầng ModelMetadata, nhưng hóa ra là có một số biến chứng xung quanh việc nhận các mục từ một thuộc tính có giá trị thu thập bằng cách sử dụng ModelMetadata. Tôi đã hack cùng một phương thức mở rộng hoạt động xung quanh đó và xây dựng một phần mở rộng ToQueryString mà bạn có thể gọi từ bất kỳ đối tượng ModelMetadata nào mà bạn có.

public static string ToQueryString(this ModelMetadata modelMetadata) 
{ 
    if(modelMetadata.Model == null) 
     return string.Empty; 

    var parameters = modelMetadata.Properties.SelectMany (mm => mm.SelectPropertiesAsQueryStringParameters(null)); 
    var qs = string.Join("&",parameters); 
    return "?" + qs; 
} 

private static IEnumerable<string> SelectPropertiesAsQueryStringParameters(this ModelMetadata modelMetadata, string prefix) 
{ 
    if(modelMetadata.Model == null) 
     yield break; 

    if(modelMetadata.IsComplexType) 
    { 
     IEnumerable<string> parameters; 
     if(typeof(IEnumerable).IsAssignableFrom(modelMetadata.ModelType)) 
     { 
      parameters = modelMetadata.GetItemMetadata() 
            .Select ((mm,i) => new { 
             mm, 
             prefix = string.Format("{0}{1}[{2}]", prefix, modelMetadata.PropertyName, i) 
            }) 
            .SelectMany (prefixed => 
             prefixed.mm.SelectPropertiesAsQueryStringParameters(prefixed.prefix) 
            );   
     } 
     else 
     { 
      parameters = modelMetadata.Properties 
         .SelectMany (mm => mm.SelectPropertiesAsQueryStringParameters(string.Format("{0}{1}", prefix, modelMetadata.PropertyName))); 
     } 

     foreach (var parameter in parameters) 
     { 
      yield return parameter; 
     } 
    } 
    else 
    { 
     yield return string.Format("{0}{1}{2}={3}", 
      prefix, 
      prefix != null && modelMetadata.PropertyName != null ? "." : string.Empty, 
      modelMetadata.PropertyName, 
      modelMetadata.Model); 
    } 
} 

// Returns the metadata for each item from a ModelMetadata.Model which is IEnumerable 
private static IEnumerable<ModelMetadata> GetItemMetadata(this ModelMetadata modelMetadata) 
{ 
    if(modelMetadata.Model == null) 
     yield break; 

    var genericType = modelMetadata.ModelType 
         .GetInterfaces() 
         .FirstOrDefault (x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>)); 

    if(genericType == null) 
     yield return modelMetadata; 

    var itemType = genericType.GetGenericArguments()[0]; 

    foreach (object item in ((IEnumerable)modelMetadata.Model)) 
    { 
     yield return ModelMetadataProviders.Current.GetMetadataForType(() => item, itemType); 
    } 
} 

sử dụng Ví dụ:

var vd = new ViewDataDictionary<Model>(model); // in a Controller, ViewData.ModelMetadata 
var queryString = vd.ModelMetadata.ToQueryString(); 

tôi đã không kiểm tra nó rất triệt để, do đó có thể có một số lỗi ref vô ẩn nấp trong nó, nhưng nó spits ra chuỗi truy vấn chính xác cho các đối tượng phức tạp Tôi đã thử.

+0

Cảm ơn rất nhiều! - điều này tỏ ra rất hữu ích khi truyền một viewmodel trở lại dịch vụ dựng hình ảnh trong trường hợp của tôi. Bạn cũng có thể thêm một phần mở rộng tĩnh thứ hai vào 'đối tượng' này (hoặc nếu bạn có một cơ sở hoặc giao diện chung trên các lớp viewmodel của bạn, chẳng hạn như' IValidatableObject'), thì bạn có thể sử dụng 'ViewModel.ToQueryString()' – StuartLC

0

@ Mã của Steve có một số lỗi nhỏ khi thêm lồng và đếm là trường hợp.

mẫu Mẫu

public class BarClass { 
    public String prop { get; set; } 
} 

public class FooClass { 
    public List<BarClass> bar { get; set; } 
} 

public class Model { 
    public FooClass foo { get; set; } 
} 

Kiểm tra Mã

var model = new Model { 
    foo = new FooClass { 
     bar = new List<BarClass> { 
      new BarClass { prop = "value1" }, 
      new BarClass { prop = "value2" } 
     } 
    } 
}; 

var queryString = new ViewDataDictionary<Model>(model).ModelMetadata.ToQueryString(); 

Giá trị của queryString nên là:

"?foo.bar[0].prop=value1&foo.bar[1].prop=value2" 

Nhưng @ đang Steve xuất ra như sau:

"?foobar[0].prop=value1&foobar[1].prop=value2" 

Cập nhật Mã

Đây là một phiên bản sửa đổi một chút dung dịch các @ Steve:

public static class QueryStringExtensions { 
    #region inner types 

    private struct PrefixedModelMetadata { 

     public readonly String Prefix; 
     public readonly ModelMetadata ModelMetadata; 

     public PrefixedModelMetadata (String prefix, ModelMetadata modelMetadata) { 
      Prefix = prefix; 
      ModelMetadata = modelMetadata; 
     } 
    } 

    #endregion 
    #region fields 

    private static readonly Type IEnumerableType = typeof(IEnumerable), 
           IEnumerableGenericType = typeof(IEnumerable<>); 

    #endregion 
    #region methods 

    public static String ToQueryString<ModelType> (this ModelType model) { 
     return new ViewDataDictionary<ModelType>(model).ModelMetadata.ToQueryString(); 
    } 

    public static String ToQueryString (this ModelMetadata modelMetadata) { 
     if (modelMetadata.Model == null) { 
      return String.Empty; 
     } 

     var keyValuePairs = modelMetadata.Properties.SelectMany(mm => 
      mm.SelectPropertiesAsQueryStringParameters(new List<String>()) 
     ); 

     return String.Join("&", keyValuePairs.Select(kvp => String.Format("{0}={1}", kvp.Key, kvp.Value))); 
    } 

    private static IEnumerable<KeyValuePair<String, String>> SelectPropertiesAsQueryStringParameters (this ModelMetadata modelMetadata, List<String> prefixChain) { 
     if (modelMetadata.Model == null) { 
      yield break; 
     } 

     if (modelMetadata.IsComplexType) { 
      IEnumerable<KeyValuePair<String, String>> keyValuePairs; 

      if (IEnumerableType.IsAssignableFrom(modelMetadata.ModelType)) { 
       keyValuePairs = modelMetadata.GetItemMetadata().Select((mm, i) => 
        new PrefixedModelMetadata(
         modelMetadata: mm, 
         prefix: String.Format("{0}[{1}]", modelMetadata.PropertyName, i) 
        ) 
       ).SelectMany(prefixed => prefixed.ModelMetadata.SelectPropertiesAsQueryStringParameters(
        prefixChain.ToList().AddChainable(prefixed.Prefix, addOnlyIf: IsNeitherNullNorWhitespace) 
       )); 
      } 
      else { 
       keyValuePairs = modelMetadata.Properties.SelectMany(mm => 
        mm.SelectPropertiesAsQueryStringParameters(
         prefixChain.ToList().AddChainable(
          modelMetadata.PropertyName, 
          addOnlyIf: IsNeitherNullNorWhitespace 
         ) 
        ) 
       ); 
      } 

      foreach (var keyValuePair in keyValuePairs) { 
       yield return keyValuePair; 
      } 
     } 
     else { 
      yield return new KeyValuePair<String, String>(
       key: AntiXssEncoder.HtmlFormUrlEncode(
        String.Join(".", 
         prefixChain.AddChainable(
          modelMetadata.PropertyName, 
          addOnlyIf: IsNeitherNullNorWhitespace 
         ) 
        ) 
       ), 
       value: AntiXssEncoder.HtmlFormUrlEncode(modelMetadata.Model.ToString())); 
     } 
    } 

    // Returns the metadata for each item from a ModelMetadata.Model which is IEnumerable 
    private static IEnumerable<ModelMetadata> GetItemMetadata (this ModelMetadata modelMetadata) { 
     if (modelMetadata.Model == null) { 
      yield break; 
     } 

     var genericType = modelMetadata.ModelType.GetInterfaces().FirstOrDefault(x => 
      x.IsGenericType && x.GetGenericTypeDefinition() == IEnumerableGenericType 
     ); 

     if (genericType == null) { 
      yield return modelMetadata; 
     } 

     var itemType = genericType.GetGenericArguments()[0]; 

     foreach (Object item in ((IEnumerable) modelMetadata.Model)) { 
      yield return ModelMetadataProviders.Current.GetMetadataForType(() => item, itemType); 
     } 
    } 

    private static List<T> AddChainable<T> (this List<T> list, T item, Func<T, Boolean> addOnlyIf = null) { 
     if (addOnlyIf == null || addOnlyIf(item)) { 
      list.Add(item); 
     } 

     return list; 
    } 

    private static Boolean IsNeitherNullNorWhitespace (String value) { 
     return !String.IsNullOrWhiteSpace(value); 
    } 

    #endregion 
} 
Các vấn đề liên quan