Comments 32
У меня свой велосипед. Кроме перечисленного — я еще беру метаданные контроллеров MVC (через GetApiExplorer), и генерирую такие вот штуки на каждый контроллер:
За счет этого, кроме того что не надо это руками писать, мне еще не надо ставить аттрибуты на viewmodels — я просто генерирую интерфейсы для всего что входит и выходит из контроллеров.
Чтобы избавится от проблемы курицы и яйца (компиляция C#, генерация TS, и компиляция TS в одном проекте) — я просто вынес MVC-код в отдельную сборку.
Кстати, твоя библиотека как-то связана с TypeLite ( http://type.litesolutions.net/ )?
module api { export var someController = { someMethod: function(id : number) : JQueryPromise<void> { return api.processRequest(`/api/someController/someMethod?id=${id}`); } } }
За счет этого, кроме того что не надо это руками писать, мне еще не надо ставить аттрибуты на viewmodels — я просто генерирую интерфейсы для всего что входит и выходит из контроллеров.
Чтобы избавится от проблемы курицы и яйца (компиляция C#, генерация TS, и компиляция TS в одном проекте) — я просто вынес MVC-код в отдельную сборку.
Кстати, твоя библиотека как-то связана с TypeLite ( http://type.litesolutions.net/ )?
У меня свой велосипед
Вот у меня тоже началось со своего велосипеда.
Просто генерирую интерфейсы для всего что входит и выходит из контроллеров
Боюсь, если я так сделаю на живом проекте сейчас — ничего хорошего не получится :) Слишком много легаси-кода, слишком много всяких недокументированных методов. Повылазиет всякого… ну его :)
MVC-код в отдельную сборку
Мне такое решение не нравится, поэтому я предпочел хирургически препарировать MSBuild-скрипт (он же .csproj).
TypeLite
Впервые слышу о ней. Обязательно посмотрю.
Про атрибуты забыл дописать:
Для некоторых экшнов я сделал такую генерацию и вот в следующем посте расскажу-покажу как. А ставить-не ставить атрибуты… ну тут палка о двух концах. В конце-то концов нам нужен всего лишь список методов (при том крайне желательно, чтобы мы могли его контролировать!).
С другой стороны плюс атрибутов в том, что можно много всякого-разного понастраивать индивидуально для метода. Это можно, было бы, конечно, изобразить Fluent-конфигурацией или, упаси б-же, XML, но пока что мне не хочется сильно разделять TypeScript и C#-код, которые его представляет.
С третьей стороны — я писал библиотечку для широкого круга пользователей и кто его знает — не все же используют именно jq-промисы. Кому-то может вообще понадобятся дополнительные фичи вроде добавления в список параметров id-шника индикатора загрузки, или еще какой радости. Или вообще обернуть это в какой-нибудь ангуляровский интерфейс для запросов к серверу. Если я сделаю фиксированное решение и скажу «делайте как я сказал» — меня, боюсь, многие матом будут крыть. :) А так — можно просто дописать пак атрибутов специально для MVC и дать возможность каждому выбрать.
P.S: А вообще у моего [TsClass] можно задать дефолтный код-генератор для всех методов класса. Так-то.
Для некоторых экшнов я сделал такую генерацию и вот в следующем посте расскажу-покажу как. А ставить-не ставить атрибуты… ну тут палка о двух концах. В конце-то концов нам нужен всего лишь список методов (при том крайне желательно, чтобы мы могли его контролировать!).
С другой стороны плюс атрибутов в том, что можно много всякого-разного понастраивать индивидуально для метода. Это можно, было бы, конечно, изобразить Fluent-конфигурацией или, упаси б-же, XML, но пока что мне не хочется сильно разделять TypeScript и C#-код, которые его представляет.
С третьей стороны — я писал библиотечку для широкого круга пользователей и кто его знает — не все же используют именно jq-промисы. Кому-то может вообще понадобятся дополнительные фичи вроде добавления в список параметров id-шника индикатора загрузки, или еще какой радости. Или вообще обернуть это в какой-нибудь ангуляровский интерфейс для запросов к серверу. Если я сделаю фиксированное решение и скажу «делайте как я сказал» — меня, боюсь, многие матом будут крыть. :) А так — можно просто дописать пак атрибутов специально для MVC и дать возможность каждому выбрать.
P.S: А вообще у моего [TsClass] можно задать дефолтный код-генератор для всех методов класса. Так-то.
Я в своем проекте использую DataContract для помечания ViewModel и все свойства, необходимые на клиенте, явно помечаю DataMember-атрибутами. При конвертации в json использую JSON.Net, который из коробки прекрасно работает с dataconract'ом. Ну и ModelBinder для всего этого написан.
Это позволяет не боятся серверных рефаткорингов даже при использовании чистого js и явно указывать, какие свойства нужны на клиенте (часть свойств вью-моделей нужны только для серверного рендеринга, гонят туда-сюда данные смысла нет). Ну и кроме того в шарпе принято свойство называть с большой буквы, а в js — с маленькой.
Отсюда вопрос: поддерживает ли ваша библиотечка dataconract?
Кстати, при конвертации в typescript generic-классы и классы с наследованием корректно генерируются?
Это позволяет не боятся серверных рефаткорингов даже при использовании чистого js и явно указывать, какие свойства нужны на клиенте (часть свойств вью-моделей нужны только для серверного рендеринга, гонят туда-сюда данные смысла нет). Ну и кроме того в шарпе принято свойство называть с большой буквы, а в js — с маленькой.
Отсюда вопрос: поддерживает ли ваша библиотечка dataconract?
Кстати, при конвертации в typescript generic-классы и классы с наследованием корректно генерируются?
Эм… я боюсь, мы как-то не поняли друг друга. Библиотечка тайпинги пишет, а не занимается сериализацией :) В свете этого не очень понятен вопрос про DataContract.
Но на всякий случай: да, тайпинги для generic-классов она тоже пишет.
Но на всякий случай: да, тайпинги для generic-классов она тоже пишет.
Попробую пояснить на примере: у меня есть ViewModel вида
из нее я бы хотел получить интерфейс вида
А в идеале даже без явного указания Name:
[DataContract]
public class OrderViewModel
{
[DataMember(Name = "itemName")]
public string ItemName { get; set; }
[DataMember(Name = "quantity")]
public int Quantity { get; set; }
public decimal Subtotal { get; set; }
public bool IsPaid { get; set; }
public string ClientName { get; set; }
public string Address { get; set; }
}
из нее я бы хотел получить интерфейс вида
interface OrderViewModel {
itemName: string;
quantity: number;
}
А в идеале даже без явного указания Name:
[DataContract]
public class OrderViewModel
{
[DataMember]
public string ItemName { get; set; }
[DataMember]
public int Quantity { get; set; }
public decimal Subtotal { get; set; }
public bool IsPaid { get; set; }
public string ClientName { get; set; }
public string Address { get; set; }
}
interface OrderViewModel {
itemName: string;
quantity: number;
}
Спасибо, ваш фич-реквест принят :)
Правда мне все еще непонятно зачем вы используете DataContract, в то время как Json.NET прекрасно справляется и без них. И к тому же имеет свой, куда более гибкий [JsonProperty]
P.S: совсем забыл — да, и с наследованием у Reinforced.Typings тоже все хорошо.
P.S: совсем забыл — да, и с наследованием у Reinforced.Typings тоже все хорошо.
Начал использовать еще до внедрения TypeScript'a. Это помогало не разломать фронтенд при рефакторинге бекэнда. С автоматической генерацией ts-интерфейсов эта проблема решается, но у нас проект большой и чистый js еще долго будет жить с нами.
Кроме того мне кажется важным явно помечать свойства, с которыми нужно работать на клиенте. Это во-первых, позволяет немного сократить объем ненужного траффика между клиентом и сервером, а во-вторых, на клиенте работать с чистыми интерфейсами без лишних серверных свойств.
Кроме того мне кажется важным явно помечать свойства, с которыми нужно работать на клиенте. Это во-первых, позволяет немного сократить объем ненужного траффика между клиентом и сервером, а во-вторых, на клиенте работать с чистыми интерфейсами без лишних серверных свойств.
Ну тут вот фиг знает. На сколько я соображаю в системном дизайне, единственная роль ViewModel-и — хранить в себе данные, которые отображаются. Переиспользовать их же на клиенте (а особенно — переиспользовать на клиенте их часть) — в некотором роде нарушение SRP. Т.е. да, я за то, чтобы View рендерился от одной модели, а на клиент уходила другая (в общем случае). Хотя на практике возникают ситуации, когда в рендер и на клиент отправляется одна и та же модель — и чувствуешь себя с этим SRP как идиот. Для таких случаев можно и [TsInterface] пошалить.
Кстати о птичках — коль пошла такая пляска — можете потыкать у Json.NET свойство атрибута… как же его… по-моему NullValueHandling — и эта радость не будет отправлять на клиент null-поля (которые там будут undefined, но при проверке через if (object.Field) это не страшно).
Ну и чтобы не разносить на два комментария — вы упомянули, что не для всех классов, которые помечены [DataContract] нужно генерировать интерфейсы. Но тогда получается что надо классы еще чем-то помечать. Мол — ты, типа, для этих генерируй, а для этих не генерируй. Можно пометить их тем же [TsInterface], что и является дефолтной практикой для R.T.
А вот, кстати, переименования автоматического у меня нет. Как-то совсем даже забыл про него. Привык на сервере и на клиенте использовать PascalCase (и можете бить меня за это тапками). Но в следующей версии сделаю.
Кстати о птичках — коль пошла такая пляска — можете потыкать у Json.NET свойство атрибута… как же его… по-моему NullValueHandling — и эта радость не будет отправлять на клиент null-поля (которые там будут undefined, но при проверке через if (object.Field) это не страшно).
Ну и чтобы не разносить на два комментария — вы упомянули, что не для всех классов, которые помечены [DataContract] нужно генерировать интерфейсы. Но тогда получается что надо классы еще чем-то помечать. Мол — ты, типа, для этих генерируй, а для этих не генерируй. Можно пометить их тем же [TsInterface], что и является дефолтной практикой для R.T.
А вот, кстати, переименования автоматического у меня нет. Как-то совсем даже забыл про него. Привык на сервере и на клиенте использовать PascalCase (и можете бить меня за это тапками). Но в следующей версии сделаю.
ViewModel хранит в себе данные, да. Часть из них мне удобнее рендерить серверно, а часть на клиенте (начали использовать реакт, но при этом разом перевести весь проект на реат невозможно). Что в этом плохого? А что такое SRP не просветите? :)
В моем случае это не поможет. У меня поля не Null, они заполнены, но на клиенте не используются.
Не имею ничего против аттрибута [TsInterface] :)
Стараюсь все же придерживаться общепринятых стандартов. В этом есть свои плюсы)
Кстати о птичках — коль пошла такая пляска — можете потыкать у Json.NET свойство атрибута… как же его… по-моему NullValueHandling — и эта радость не будет отправлять на клиент null-поля (которые там будут undefined, но при проверке через if (object.Field) это не страшно).
В моем случае это не поможет. У меня поля не Null, они заполнены, но на клиенте не используются.
Ну и чтобы не разносить на два комментария — вы упомянули, что не для всех классов, которые помечены [DataContract] нужно генерировать интерфейсы. Но тогда получается что надо классы еще чем-то помечать. Мол — ты, типа, для этих генерируй, а для этих не генерируй. Можно пометить их тем же [TsInterface], что и является дефолтной практикой для R.T.
Не имею ничего против аттрибута [TsInterface] :)
А вот, кстати, переименования автоматического у меня нет. Как-то совсем даже забыл про него. Привык на сервере и на клиенте использовать PascalCase (и можете бить меня за это тапками). Но в следующей версии сделаю.
Стараюсь все же придерживаться общепринятых стандартов. В этом есть свои плюсы)
Кстати про важные на клиенте свойства — в моем [TsInterface] вы можете явно сказать AutoExportProperties = false и пометить [TsProperty] те проперти (и через [TsField] те филды), которые должны быть экспортированы. При желании указав для них кодогенератор. И даже автоматическую букву I перед интерфейсами можете отключить. :)
При наличии этой информации, фич-реквест еще актуален?
При наличии этой информации, фич-реквест еще актуален?
Я тебе советую взять JSON.NET, в него легко встраивается конвертация имен: PersonName => personName при сериализации, и обратно при десериализации, делается автоматом без доп. аттрибутов.
http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Serialization_CamelCasePropertyNamesContractResolver.htm
http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Serialization_CamelCasePropertyNamesContractResolver.htm
Вообще, меня давно и прочно будоражит идея тесной интеграции Back-End и Front-End на .NET стеке, что в свою очередь даже вылилось в попытку с наскоку написать целый транслятор из C# в JavaScript.
Чем не устроили существующие трансляторы, коих сейчас и так много существует List of languages that compile to JS.
Темой тесной интеграции я тоже занимался, правда давно уже: Универсальный код C# под .NET и JavaScript. Сейчас бы, понятное дело, использовал другие инструменты.
Чем не устроили существующие трансляторы
Вы бы знали сколько раз мне задавали этот вопрос. Самый честный ответ: потому что я несколько по-своему вижу Use-Cases транслятора и имею свои представления о usability и flexibility такой штуки. Обратите внимание — ни один из предложенных вариантов не используют как «стандарт индустрии де-факто» и, в общем-то, все понимают почему (затруднена интеграция с MVC-проектом — тот же Script# подменяет mscorlib — то есть в одну сборку с проектом транслируемые классы уже не положишь, затруднена отладка, не очень понятно что у этих продуктов с расширяемостью, ну и много других мелких нюансов — не могу сходу перечислить). У меня свое видение, как это все должно работать, отлаживаться и тестироваться, по сему я и предпочел попытаться сделать свое. К слову, получилось в некотором роде похоже на DuoCode.
Ну так не лучше ли взять какой-нибудь существующий, на рослине или нет, и доработать? С нуля довольно много придется разрабатывать. А Script# по факту давно устарел уже, сейчас его уже не имеет смысла использовать.
Я на Roslyn и написал уже, собсно, ту самую версию, которая ушла в анабиоз (при том вот сразу через пару дней после выхода Roslyn-а — пришлось Microsoft.CodeAnalyzis выдирать с мясом из исходников). Так что мне не привыкать много разрабатывать :).
Там, на самом деле, затык в том, что в TS называется тайпинги. Т.е. придется переписывать интерфейсы для внешний библиотек, что руками делать долго и скучно.
А на самом деле, первоначальная версия транслятора внезапно хороша тем, что там есть парсер JavaScript, который превосходно разбирает даже минифицированный jquery в AST. Не спрашивайте зачем он там нужен, но он есть.
Там, на самом деле, затык в том, что в TS называется тайпинги. Т.е. придется переписывать интерфейсы для внешний библиотек, что руками делать долго и скучно.
А на самом деле, первоначальная версия транслятора внезапно хороша тем, что там есть парсер JavaScript, который превосходно разбирает даже минифицированный jquery в AST. Не спрашивайте зачем он там нужен, но он есть.
Хорошая грамматика для JavaScript внезапно есть в ANTLR: ECMAScript.g4. :)
Commits on Apr 24, 2014
@bkiers
Added an ECMAScript grammar.
А я свою грамматику (на Coco\R) написал где-то в марте прошлого года. Время, беспощадная ж ты штука.
А вообще то ли у меня руки не оттуда, то ли лыжи не едут… Но в общем была у меня какая-то грамматика для ANTLR-а, из которой я сгенерил все необходимое, сделал playground для тестирования, нажал F5 — и получил зацикливание на простеньком js-файле. С тех пор я ANTLR-ом не пользуюсь.
Ну так вообще-то в апреле появилась грамматика для 4 версии ANTLR. Судя по этому сайту, грамматика ECMAScript существует аж с 2008 года: www.antlr3.org/grammar/list.html
Скорее всего вы не разобрались с устройством ANTLR и его грамматик. Я вот тоже раньше не разбирался в лексических режимах, предикатах и других вещах. А после того, как прочитал книгу и попрактиковался я понял, что это очень мощный инструмент, обладающий большими возможностями по разбору формальных языков, в том числе и контекстно-зависимых. Сейчас вот на работе занимаюсь грамматикой для PHP.
Но в общем была у меня какая-то грамматика для ANTLR-а, из которой я сгенерил все необходимое, сделал playground для тестирования, нажал F5 — и получил зацикливание на простеньком js-файле. С тех пор я ANTLR-ом не пользуюсь.
Скорее всего вы не разобрались с устройством ANTLR и его грамматик. Я вот тоже раньше не разбирался в лексических режимах, предикатах и других вещах. А после того, как прочитал книгу и попрактиковался я понял, что это очень мощный инструмент, обладающий большими возможностями по разбору формальных языков, в том числе и контекстно-зависимых. Сейчас вот на работе занимаюсь грамматикой для PHP.
Я как бы и не говорю что «виновата скамейка», нет :) Просто с ANTLR-ом у меня был неудачный первый опыт (который во многом влияет на восприятие технологии как таковой) и как-то так получилось что я перешел на Coco\R и вот я здесь.
Дадада. Вот оттуда я ее скачал и сгенерил парсер, который зациклился на самом простом js-файле.
www.antlr3.org/grammar/list.html
Дадада. Вот оттуда я ее скачал и сгенерил парсер, который зациклился на самом простом js-файле.
в Web essentials для visual studio сейчас есть возможность сгенерить ts-файлик с C# класса + при изменении класса файлик будет изменяться автоматичски
Sign up to leave a comment.
Reinforced.Typings — библиотека для автоматической генерации TypeScript-тайпингов и не только