Мой контроллер MVC должен действительно знать о JSON?

Если я правильно понимаю ваши потребности, вам нужно отсортировать вывод таким образом, чтобы строки #temp1 отображались перед #temp2 строками для каждого значения cid.

То, что вы могли бы сделать, - это сгенерировать дополнительный столбец ordnum, присваивая значения для каждой таблицы только для целей сортировки, а затем избавиться от него во внешнем операторе select.

select cid, _data
from (
  select 1 as ordnum, * 
  from #temp1 
  union all
  select 2 as ordnum, * 
  from #temp2 t2
  where exists (
    select 1
    from #temp1 t1
    where t1.cid = t2.cid
    )
  ) q
order by cid, ordnum

Я также переписал ваше условие where для эквивалента, который должен работать быстрее, используя оператор exists.

Live DEMO - нажмите меня!

Вывод

cid     _data
1001    text1
1001    text2
1001    sample1
1001    sample2
1002    text1
1002    text2
1002    sample1
1002    sample2

22
задан Community 23 May 2017 в 11:45
поделиться

7 ответов

Я думаю, что Вы рассерженные ни по чему. Таким образом, что, если контроллер знает о JSON в своем открытом интерфейсе?

мне когда-то сказали: "Сделайте свой код универсальным, не подавайте свою универсальную заявку".

Вы пишете Контроллер Приложения здесь. Для Контроллера Приложения - хорошо, чья ответственность состоит в том, чтобы смягчить между моделью и представлениями и вызвать изменения в модели - для знания об определенном представлении (JSON, HTML, PList, XML, YAML).

В моих собственных проектах, у меня обычно есть что-то как:

interface IFormatter {
    ActionResult Format(object o);
}
class HtmlFormatter : IFormatter {
    // ...
}
class JsonFormatter : IFormatter {
    // ...
}
class PlistFormatter : IFormatter {
    // ...
}
class XmlFormatter : IFormatter {
    // ...
}

В основном "средства форматирования", которые берут объекты и дают им другое представление. HtmlFormatter с даже достаточно умны к таблицам выходных данных, если их объект реализует IEnumerable.

Теперь контроллеры, которые возвращают данные (или это может генерировать части веб-сайта с помощью HtmlFormatter, с берут аргумент "формата":

public ActionResult JoinMailingList(string txtEmail, string format) {
    // ...
    return Formatter.For(format).Format(
        new { foo = "123", success = true }
    );
}

Вы могли добавить свое "объектное" средство форматирования для Ваших модульных тестов:

class ObjectFormatter : IFormatter {
    ActionResult Format(object o) {
        return new ObjectActionResult() {
            Data = o
        };
    }
}

Используя эту методологию, любой из Ваших вызовов queries/actions/procedures/ajax, независимо от того, что Вы хотите назвать их, может произвести во множестве форматов.

10
ответ дан 29 November 2019 в 05:31
поделиться

Обычно я стараюсь не беспокоиться об этом. В Asp.Net MVC достаточно разделения проблем, чтобы свести утечку к минимуму. Вы правы, хотя; при тестировании возникает некоторое препятствие.

Вот тестовый помощник, который я использую, и он хорошо работает:

protected static Dictionary<string, string> GetJsonProps(JsonResult result)
{
    var properties = new Dictionary<string, string>();
    if (result != null && result.Data != null)
    {
        object o = result.Data;
        foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(o))
            properties.Add(prop.Name, prop.GetValue(o) as string);
    }
    return properties;
}

Вы можете использовать метод расширения Request.IsAjaxRequest () для возврата различных типов ActionResult:

if (this.Request != null && this.Request.IsAjaxRequest())
    return Json(new { Message = "Success" });
else
    return RedirectToAction("Some Action");

Примечание: вам понадобится Request! = Null, чтобы не прерывать ваши тесты.

7
ответ дан 29 November 2019 в 05:31
поделиться

Я не слишком волнуюсь по поводу возврата JSon, как я был прежде. Природа Ajax, кажется, такова, что сообщение, которое Вы хотите обработать в JavaScript только, касается той ситуации с Ajax. Потребность Ajax в производительности просто должна влиять на код так или иначе. Вы, вероятно, не хотели бы возвращать те же данные другому клиенту.

вещи Пары относительно тестирования JSonResult, который я заметил (и я все еще должен все же записать любые тесты для своего приложения):

1), когда Вы возвращаете JSonResult из своего метода действия, который 'получен' Вашим методом тестирования, у Вас все еще есть доступ к исходному Объекту данных. Это не было очевидно для меня сначала (несмотря на то, чтобы быть несколько очевидным). Ответ Rob выше (или возможно ниже!) использует этот факт, чтобы взять параметр Данных и создать словарь из него. Если Данные имеют известный тип затем, конечно, можно бросить их к тому типу.

Лично я только возвращал очень очень простые сообщения через Ajax без любой структуры. Я придумал дополнительный метод, который мог бы быть полезен для тестирования, если Вам просто создали простое сообщение из анонимного типа. Если у Вас есть больше чем один 'уровень' к Вашему объекту - Вы - вероятно, более обеспеченное создание фактического класса для представления объекта JSon так или иначе, в этом случае Вы просто бросаете jsonResult.Data к тому типу.

Демонстрационное использование сначала:

Метод действия:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ContactUsForm(FormCollection formData){

     // process formData ...

     var result = new JsonResult()
     {
          Data = new { success = true, message = "Thank you " + firstName }
     };

     return result;
}

Модульный тест:

var result = controller.ContactUsForm(formsData);
if (result is JSonResult) {

     var json = result as JsonResult;
     bool success = json.GetProperty<bool>("success");
     string message = json.GetProperty<string>("message");

     // validate message and success are as expected
}

можно затем выполнить утверждения или независимо от того, что Вы хотите в своем тесте. Кроме того, дополнительный метод выдаст исключения, если тип не будет как ожидалось.

Дополнительный метод:

public static TSource GetProperty<TSource>(this JsonResult json, string propertyName) 
{
    if (propertyName == null) 
    {
        throw new ArgumentNullException("propertyName");
    }

    if (json.Data == null)
    {
        throw new ArgumentNullException("JsonResult.Data"); // what exception should this be?
    }

    // reflection time!
    var propertyInfo = json.Data.GetType().GetProperty(propertyName);

    if (propertyInfo == null) {
        throw new ArgumentException("The property '" + propertyName + "' does not exist on class '" + json.Data.GetType() + "'");
    }

    if (propertyInfo.PropertyType != typeof(TSource))
    {
        throw new ArgumentException("The property '" + propertyName + "' was found on class '" + json.Data.GetType() + "' but was not of expected type '" + typeof(TSource).ToString());
    }

    var reflectedValue = (TSource) propertyInfo.GetValue(json.Data, null);
    return reflectedValue;
}
4
ответ дан 29 November 2019 в 05:31
поделиться

Я думаю, что у вас есть правильная точка зрения - почему бы не делегировать «разрешенные типы ответов по сравнению с созданными типами ответов» в какое-то место, где они действительно принадлежат?

Это напоминает мне одно из мнений Джереми Миллера о том, как сделать приложение ASP.NET MVC: «Мнения» о ASP.NET MVC

В их В приложении все действия контроллера имеют простой и понятный интерфейс - один объект модели представления входит, другой объект модели представления удаляется.

2
ответ дан 29 November 2019 в 05:31
поделиться

Я не уверен, насколько большой из проблемы это на самом деле, но "альтернативный шаблон" для следования в ASP.NET, который MVC должен был бы записать JSON ViewEngine. Это на самом деле не было бы настолько трудно, так как функциональность JSON, встроенная в платформу, сделает большую часть тяжелого подъема для Вас.

я действительно думаю, что это было бы лучшим дизайном, но я не уверен, что настолько лучше, что стоит идти вразрез с "официальным" способом реализовать JSON.

1
ответ дан 29 November 2019 в 05:31
поделиться

Я думал об этом и реализовал фильтр JsonPox , чтобы сделать это.

1
ответ дан 29 November 2019 в 05:31
поделиться

С другой стороны, если Вы не хотите входить в использование отражения, можно создать RouteValueDictionary со Свойством данных результата. Движение с данными OP...

var jsonData = new RouteValueDictionary(result.Data);
Assert.IsNotNull(jsonData);

Assert.AreEqual(2,
                jsonData.Keys.Count);

Assert.AreEqual("123",
                jsonData["foo"]);

Assert.AreEqual(true,
                jsonData["success"]);
0
ответ дан 29 November 2019 в 05:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: