TypeScriptプロジェクトで既存のC#クラス定義を再利用する方法


121

TypeScriptエンティティフレームワークドメインモデルが既に存在するMVCプロジェクトに属するHTMLクライアントプロジェクトで使用を開始します。2つのチームがこれに取り組むので、2つのプロジェクト(クライアント側とサーバー側)を完全に分離したい...オブジェクトのやり取りにはJSONとRESTを使用します。

もちろん、domainクライアント側のオブジェクトはサーバー側のオブジェクトと一致する必要があります。以前は、通常これを手動で行っていました。POJOTypeScriptで対応するクラスを作成するために、C#クラス定義(特にドメインモデルのクラス)を再利用する方法はありますか?


いいえ、まったく別の言語です。
ハンスパッサント

6
はい私はPOCOを意味しました。私はそれらが完全に異なる言語であることを知っています...しかし、何とかしてこれをすべて入力することを避けるのは素晴らしいことです...私は今のところc#コードをコピーして貼り付け、コンパイルされるまでそれをリファクタリングすると思いますTypeScript ...そうすれば、属性を間違って入力しなかったことが確実になり、覚えておく必要がなくなります。しかし、これは明らかにいい音ではありません。
pabloelustondo 2012年

1
TypescriptモデルクラスからC#モデルクラスへ、JSONを介して双方向に逆シリアル化可能な他の方向にも興味があります。
Jason Kleban 2013年

私は同じものを探していましたが、このGulpプラグインを偶然見つけましたが、それがどの程度サポートされているのかはわかりません
Luke T O'Brien

回答:


54

現在、C#をTypeScriptにマップするものはありません。POCOがたくさんある場合、またはPOCOが頻繁に変更されると思われる場合は、コンバーターを作成できます。

public class MyPoco {
    public string Name { get; set; }
}

export class MyPoco {
    public Name: string;
}

C#からの自動生成に関するCodeplexについての議論もあります。

TypeLiteは、物事を最新の状態に保つために、C#からTypeScriptインターフェイスを生成できます。

http://type.litesolutions.net/


うん、このようなものは私が手動でやろうと思っていたものです。今、コンバーターを書く時間があるかどうかわかりませんが、そうです、それがアイデアです。ありがとう。マイクロソフトが私たちが話している間、今それをやっているだけかもしれません。
pabloelustondo 2012年

これは、2つの方法のいずれかで行うことができます... EnvDTEオートメーションの助けを借りて、またはMefディレクトリカタログとリフレクション/イントロスペクションを使用して、.tsファイルを生成します。視覚に依存しないため、2番目の方が好きです。
Arek Bal '19

1
私はdartを使い始めていて、c#とjavascriptの間で型を共有する方法の同じ問題に遭遇しました。この問題がTypescriptによって解決されることを望みましたが、答えはまだではないようです。私は少しはむしろうまくJavaScriptに#cをコンパイルsaltarelleコンパイラによって台無しでもあったsaltarelle-compiler.com
BraveNewMath

2
@DanielHarvey列挙型はTypeLiteによって正しく生成されますが、コメント以降は修正されています。
pauloya 14

1
TypeScriptPasteはC#をTypescriptに変換します。Roslynコンパイラー(つまり、Visual Studio 2015)が必要ですが、それは非常にうまく機能します。それは100%ではなく、いくつかのコードを簡略化しなければなりませんでした-foreachをforループに変換し、たとえば、独自のList <T>クラスを記述します。で動作しますが、VSでコードを変更およびテストし、TypeScriptを介してJavascriptに「コンパイル」できることを支払うのに少額の費用がかかりました。
John Mott

36

Web Essentials.d.tsでは、保存時にC#ファイルをTypeScript ファイルにコンパイルできます。次に、.tsファイルから定義を参照できます。

ここに画像の説明を入力してください


おそらく.tsファイルとc#を混同していますか?このオプションが見つかりません
フローレス

1
しかし、いくつかの検索を行った後、私はあなたが何を意味するのかを発見しました。
Flores 14

2
実際にはそうではありません。操作が何も「コンパイル」しないことは確かです。コードを生成します。それは私を混乱させましたが、99%正しくはありません。それをお伝えします;-)
フローレス

1
名前空間といくつかのカスタマイズを構成できれば、より便利でした。
Farshid Saberi

5
これを使用するには、「TypeScript Definition Generator」を手動でインストールする必要があります。ここを
Taran

24

上記のTypeLiteとT4TSはどちらも良さそうでしたが、TypeLiteを1つ選び、サポートを得るために分岐しました

  • ValueTypes
  • ヌラブル
  • camelCasing(TypeScriptルートドキュメントはラクダを使用しており、これはC#と組み合わせるとうまくいきます)
  • パブリックフィールド(クリーンで読みやすいPOCOが大好きで、C#コンパイラでも簡単に使用できます)
  • モジュールの生成を無効にする

次に、C#インターフェイスが必要で、自分の物を焼くときがきたと思って、必要なことだけを実行する単純なT4スクリプトを作成しました。Enumも含まれます。リポジトリは必要ありません。T4が100行未満です。

使用法
ライブラリなし、NuGetなし、この単純な単純なT4ファイル-Visual Studioで「アイテムの追加」を使用し、任意のT4テンプレートを選択します。次に、これをファイルに貼り付けます。「ACME」を含むすべての行を適応させます。すべてのC#クラスについて、行を追加します

<#= Interface<Acme.Duck>() #>

順序が重要です。次のインターフェースでは、既知のタイプが使用されます。インターフェースのみを使用する場合、ファイル拡張子は.d.tsにすることができます。列挙型の場合、変数がインスタンス化されるため、.tsファイルが必要です。

カスタマイズ
スクリプトをハックします。

<#@ template debug="true" hostSpecific="true" language="C#" #>
<#@ output extension=".ts" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ assembly name="$(TargetDir)ACME.Core.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Linq" #>

<#= Interface<Acme.Bunny>() #>
<#= Interface<Acme.Duck>() #>
<#= Interface<Acme.Birdy>() #>
<#= Enums<Acme.CarrotGrade>() #>
<#= Interface<Acme.LinkParticle>() #>

<#+  
    List<Type> knownTypes = new List<Type>();

    string Interface<T>()
    {   
        Type t = typeof(T);     
        var sb = new StringBuilder();
        sb.AppendFormat("interface {0} {{\n", t.Name);
        foreach (var mi in GetInterfaceMembers(t))
        {
            sb.AppendFormat("  {0}: {1};\n", this.ToCamelCase(mi.Name), GetTypeName(mi));
        }
        sb.AppendLine("}");
        knownTypes.Add(t);
        return sb.ToString();
    }

    IEnumerable<MemberInfo> GetInterfaceMembers(Type type)
    {
        return type.GetMembers(BindingFlags.Public | BindingFlags.Instance)
            .Where(mi => mi.MemberType == MemberTypes.Field || mi.MemberType == MemberTypes.Property);
    }

    string ToCamelCase(string s)
    {
        if (string.IsNullOrEmpty(s)) return s;
        if (s.Length < 2) return s.ToLowerInvariant();
        return char.ToLowerInvariant(s[0]) + s.Substring(1);
    }

    string GetTypeName(MemberInfo mi)
    {
        Type t = (mi is PropertyInfo) ? ((PropertyInfo)mi).PropertyType : ((FieldInfo)mi).FieldType;
        return this.GetTypeName(t);
    }

    string GetTypeName(Type t)
    {
        if(t.IsPrimitive)
        {
            if (t == typeof(bool)) return "bool";
            if (t == typeof(char)) return "string";
            return "number";
        }
        if (t == typeof(decimal)) return "number";            
        if (t == typeof(string)) return "string";
        if (t.IsArray)
        {            
            var at = t.GetElementType();
            return this.GetTypeName(at) + "[]";
        }
        if(typeof (System.Collections.IEnumerable).IsAssignableFrom(t)) 
        {
            var collectionType = t.GetGenericArguments()[0]; // all my enumerables are typed, so there is a generic argument
            return GetTypeName(collectionType) + "[]";
        }            
        if (Nullable.GetUnderlyingType(t) != null)
        {
            return this.GetTypeName(Nullable.GetUnderlyingType(t));
        }
        if(t.IsEnum) return "number";
        if(knownTypes.Contains(t)) return t.Name;
        return "any";
    }

    string Enums<T>() // Enums<>, since Enum<> is not allowed.
    {
        Type t = typeof(T);        
        var sb = new StringBuilder();        
        int[] values = (int[])Enum.GetValues(t);
        sb.AppendLine("var " + t.Name + " = {");
        foreach(var val in values) 
        {
            var name = Enum.GetName(typeof(T), val);
            sb.AppendFormat("{0}: {1},\n", name, val);
        }
        sb.AppendLine("}");
        return sb.ToString();
    }
#>

スクリプトの次のレベルは、MVC JsonControllerクラスからサービスインターフェイスを作成することです。


1
とてもかわいいですがtypeof(ParticleKind)、あなたはあなたの中にいますEnum<T>。確かにそうtypeof(T)でしょうか?また、それ以降のTypeScriptバージョンに対応boolするように更新する必要がありbooleanます
Gone Coding

また、これはクラスの列挙型プロパティで壊れます
Gone Coding

1.うーん、はい、頭を上げてくれてありがとう、それを修正します。2. Typescriptは、このスクリプトを作成してから進化しました。更新が必要なようですが、間違いなく正しいです。あなた自身の目的のための出発点として役立つことを願っています。
シティキッド2016

1
私はそれをヘルパーライブラリに変換し、バグを修正して、TTファイルの1行のエントリだけを使用してインターフェイスと新しいを生成しましたconst enum。例をありがとう。それは非常に近かったので、作業結果がはるかに速くなりました。
コーディング終了

23

vscodeを使用している場合は、まさにそれを行う私の拡張機能csharp2tsを使用できます。

貼り付けたC#コードを選択してConvert C# to TypeScript、コマンドパレットからコマンド を実行するだけですここに画像の説明を入力してください 。変換例:

public class Person
{
    /// <summary>
    /// Primary key
    /// </summary>
    public int Id { get; set; }

    /// <summary>
    /// Person name
    /// </summary>
    public string Name { get; set; }
}

export interface Person
{
    /**Primary key */
    Id : number;

    /**Person name */
    Name : string;
}

1
msbuildでコンパイルするとtypescript定義が出力される前に出力される、完全に自動化されたソリューションに関心があると思います。プラグインを使用してそれを取得する方法はありますか?
binki 2018年

いいえ、これはVSCodeプラグインであり、スタンドアロンプ​​ログラムとしてではなく、エディタ内でのみ機能します
Rafael

node.jsまたはtytpescriptを使用する場合は、このvscode拡張機能をノードモジュールに変換します。ここでリポジトリを確認できます:github.com/YuvrajSagarRana/csharp-to-typescript
Sagar Rana Magar

コマンドをキーボードショートカットにリンクする方法はありますか?たとえば、.netコードを選択し、shift + ctrl + cをセットアップして「C#をTypeScriptに変換」を実行すると、プロセスが高速化されます。プラグインが好きです!
Pawel Cioch

18

これを解決するための私のアプローチを以下に示します。属性を使用してC#クラスを宣言すると、.d.ts-filesが生成されます(T4変換を使用して)。nugetにパッケージがあり、ソースはgithubから入手できます。私はまだプロジェクトに取り組んでいますが、サポートはかなり広範囲です。


私はこのプロジェクトをフォークして、ここにノックアウトサポートを追加しました:github.com/omniscient/t4ts
Frank.Germain

18

Visual Studioを使用している場合は、Typewriter拡張機能を追加します。

Visual Studioギャラリー

ウェブサイト/ドキュメント

更新

Web Essentialsは VS 2015にインストールされ、あなたがクラスファイルを右クリックすることができ、その後、>ウェブエッセンシャル>コンテキストメニューから活字体インテリセンスファイルを作成します。


それはインテリセンスのサポートのためにd.tsファイルを作成しましたが、それをどのように使用し、そして基礎となるクラスの作成との関係は何ですか?私はWebEssentailsに行って、ドキュメントを見つけることができません。助言がありますか?TIA。
ハワードロ2017年

@hio使用する必要がある.tsファイルでd.tsファイルを参照するだけです。クラスを変更すると、基になるd.tsファイルが更新されます(ヒント:d.tsをドラッグアンドドロップできます)ファイルを.tsファイルの先頭に追加すると、参照が作成されます。)
Michael Tranchida

マイケル、ありがとう!d.tsファイルを空の.tsファイルにドロップしようとすると、ファイルが含まれているフォルダーにのみ追加されました。VS2015と新しいVS2017で試してみましたが、結果は同じです。これがどのように機能するかを示すビデオまたはチュートリアルを知っていますか?TIA
howardlo

エディターでd.tsファイルを.tsファイルにドロップしてみましたが、参照が作成されました。私は今理解したと思います。チュートリアルはまだ歓迎されています。ありがとう!
ハワードロ2017

@hlo申し訳ありませんが、チュートリアルを知りません。Web Essentialsのルートに行くとき、ドメインモデルがクラスライブラリにあり、クライアント側のコードにあるため、通常、ブラウザーが必要とするdtoモデルまたはvmモデルを作成する必要があるため、.tsファイルを複製しています。について知る。これらすべてに問題がある場合は、タイプライター拡張機能を試してください。ur .tsモデルファイルを好きな場所に置くことができます。
Michael Tranchida、2017

15

Reinforced.Typingsフレームワークを試してください。それはあなたの問題を解決するようです。

  1. NuGetからインストールする
  2. POCOに移動し、その上に[TsInterface]属性を追加します

    using Reinforced.Typings.Attributes;
    namespace YourNamespace {
        [TsInterface]
        public class YourPoco
        {
            public int YourNumber { get;set; }
            public string YourString { get;set; }
            public List<string> YourArray { get;set; }
            public Dictionary<int, object> YourDictionary { get;set; }
        }
    }
  3. プロジェクトを再構築する
  4. 生成されたTypeScriptコードを%Your_Project_Directory%/Scripts/project.tsファイルで見つけ、手動でプロジェクトに追加します

    module YourNamespace {
        export interface IYourPoco
        {
            YourNumber: number;
            YourString: string;
            YourArray: string[];
            YourDictionary: { [key: int]: any };
        }
    }
  5. すべてのPOCOについて同じことをproject.ts行い、他のTypeScriptコードで参照します。

詳細については、ドキュメントWikiを参照してください


URLのみを共有するのではなく、サンプルスニペットを追加します
Venkat.R

wikiにはクイックスタートO_Oであり github.com/reinforced/Reinforced.Typings/wiki
パベルB.ノビコフ

しかし、わかりました、ここに例を示します:)
Pavel B. Novikov

.NET Coreサポートなし(リンク):(
Alex Klaus

5
@AlexKlaus .NET Coreサポートが到着しました
Pavel B. Novikov

10

C#クラスからTypeScriptインターフェイスを生成できる小さなユーティリティを作成しました。NuGetパッケージとして入手できます。詳細なドキュメントは、プロジェクトのWebページにあります。


素敵な図書館、努力。残念ながら、生成された値の型を調整する方法が見つかりませんでした。たとえば、「string」を「KnockoutObservableString」に変換したり、「string []」を「KnockoutObservableArray」に変換したりできます。それは近い将来の計画にあるものですか?
ルート

2
代わりにT4TSを使用しましたが、14分かかりました。
ルート

@root、生成された定義で実際にstring []をKnockoutObservableArrayに変換しないでください。これらのクラスのシリアル化されたインスタンスを実際に使用しているときに、これらの生成された定義を使用します。これで、マッピングプラグインを介してオブジェクト全体を実行している可能性がありますが、これには注意が必要です。それは過剰になる可能性があり、私は常にC#クラスのシリアル化されたインスタンスからオブザーバブルでいっぱいのTypeScriptクラスに手動で(おそらくctorを介して)変換することを好みます。マッピングプラグインで盲目的に実行することをお勧めするのは、CRUDスタイルのアプリの場合のみです。
アレンライス14

:@Lukas Kabrtは、それが私たちのプロジェクトでは非常に有益となっていると、私はここで簡単にそれについて書いた、TypeLiteのためにそんなにありがとうunderwatergorilladome.com/...
アレン・ライスを

@AllenRice、私は手作りのKnockoutビューモデルクラスがあると便利だと思いました。ここでは、説明したアプローチを使用して、マッピングプラグインを通じて渡されたDTOである自動生成クラスと組み合わせています。
ルート

7

このライブラリタイプライターをご覧ください

クラス、列挙型、インターフェースなどだけでなく、単に素晴らしいapi-controllersも変換します。

さらに、ソース.csファイルを保存するとすぐにこれが行われるため、外部ツールを起動する必要はありません。.csを保存すると、.tsが更新されます


素晴らしいことは、対応するCSファイルの保存時にTSファイルを生成することです。ただし、出力フォルダーの設定は非常に壊れやすく(ここでの説明を参照)、手作りのコードが必要です。
アレックスクラウス

私はそのためにビルドツールを使用していますが、このツールはここで述べたほとんどのものよりもはるかに強力です
harishr

6

T4テンプレートを使用する小さなソリューションがあります(ソースを表示)。

あなたはどんなCLR POCOからでも行く:

public class Parent : Person
{
    public string Name { get; set; }
    public bool? IsGoodParent { get; set; }
    public virtual ICollection<Child> Children { get; set; }
}

TypeScriptインターフェースへ:

///<reference path="Child.d.ts" />
///<reference path="Person.d.ts" />
interface Parent extends Person {
    Name : string;
    IsGoodParent? : bool;
    Children : Child[];
}

3

オープンソースプロジェクトのNSwagを使用できます。GUIでは、既存の.NET DLLから.NETクラスを選択し、そのためのTypeScriptインターフェイスを生成できます。

このプロジェクトは、コマンドラインツールとT4テンプレートのサポート、およびWeb APIコントローラーのクライアントコードの生成も提供します...


NSwagがTSファイルを生成するのは、バイナリファイル(バイナリのすべての依存関係も必要)か、Swaggerがバイナリファイルから生成するJSONファイルのどちらかだけであることを認識してください。
Alex Klaus

3

生成されたTypeScriptクラス/インターフェイスごとに個別のファイルを作成する必要がある場合(つまり、「ファイルごとに1つのクラス」の方法で)、TypeGenを試すことができます。これは、パッケージマネージャーコンソールからC#クラス/列挙型に基づいてTypeScriptファイルを生成するために使用できるツールです。現在サポートしています:

  • 列挙型のエクスポート; POCOをTSクラスまたはインターフェースとしてエクスポート
  • 継承
  • ジェネリック型
  • コレクション/ネストされたコレクションタイプ

プラスいくつかの追加機能。また、オープンソースです(githubで確認できます)。


2

逆はどうですか?

erecruit TypeScript Translatorをチェックしてください。すぐに使えるC#サポートが付属していますが、実際にはテンプレートベース(レンダリングにNunjucksを使用)です。つまり、VB.NET、F#、C ++、XML、SQLなど、テンプレートでエンコードできるものなら何でも生成できます。

.NETコンソールプログラム、NodeJSプログラム(Windows以外のプログラムの場合)、またはVisual Studio拡張機能として機能し、生成時に保存機能を備えています。また、ビルドサーバーを満足させるためのMSBuildサポートが含まれています。:-)


私はこれを+1しました。なぜなら、それが本当に最良のソリューションであり、生成時保存がキラー機能だからです。
John Zabroski、2016年

2

これを使用することもできます:https : //github.com/pankleks/TypeScriptBuilder

この小さなライブラリは、C#型に基づいてTypeScript型定義を生成します。バックエンドC#プロジェクトで直接使用して、フロントエンドTypeScriptプロジェクトのコードを生成します。小さなコンソールアプリを作成して、事前ビルドツールでコードを生成することもできます。

フル&NET Coreフレームワークで動作します!

nugetによるインストール: Install-Package TypeScriptBuilder

サポートされている機能

  • タイプ依存関係の解決
  • ジェネリック
  • 型の継承
  • 名前空間(モジュール)
  • 列挙型
  • null許容型
  • 辞書の変換(強い型のTSインデックス付きオブジェクトへ)
  • コード生成制御属性のセット
  • any 変換できないタイプの場合

詳細:https : //github.com/pankleks/TypeScriptBuilder/blob/master/README.md


試してみTypeScriptBuilderたところ、これまでのところ優れています。.NET Coreをサポートします!
Tobias J

1

みんなはhttps://github.com/ 強化/ Reinforced.Typingsを見てください。私は過去数日間、typeliteとt4テンプレートで遊んでいて、このプロジェクトで終わりました。それは超シンプルで魅力のように機能します。パッケージを入手し、構成ファイルを変更して(10秒程度)、ビルドします。すべてが問題なく自動的に行われます。著者を祝福してください!

T4テンプレートの悪い点は、VSからビルドすると、スキャンされたアセンブリがロックされ、VSを再起動する必要があることです(これはばかげていますか?)。T4 Toolboxにいくつかの回避策といくつかのVSクリーニングディレクティブがありますが、これらのどれも私にはうまくいきませんでした。


1

シティキッドソリューションが好きです。少し延長しました。したがって、ソリューションはT4テンプレートを使用したコード生成技術にも基づいています。

一般的なTypeScriptタイプとアンビエント宣言を生成できます。

継承とインターフェースの実装をサポートしています。

タイプフィールドとしてジェネリック、配列、リストをサポートします。

また、構成で明示的に言及されていないTypeScriptタイプに変換されます(たとえば、タイプAをインポートし、TS出力では、フィールドのタイプ、基本タイプ、インターフェースなど、他のタイプを見つけることができます)。

タイプの名前を上書きすることもできます。

列挙型もサポートされています。

使用例(プロジェクトリポジトリで確認できます):

// set extension of the generated TS file
<#@ output extension=".d.ts" #>

// choose the type of TS import TsMode.Ambient || TsMode.Class
<# var tsBuilder = new TsBuilder(TsMode.Ambient); #>

// reference assembly with the c# types to be transformed
<#@ assembly name="$(SolutionDir)artifacts\...\CsT4Ts.Tests.dll" #>

// reference namespaces
<#@ import namespace="CsT4Ts.Tests" #>
<#
    //add types to processing
    tsBuilder.ConsiderType(typeof(PresetDTOBase), "PresetBase");
    tsBuilder.ConsiderType(typeof(PresetDTO), "Preset");
    tsBuilder.ConsiderType(typeof(TestInterface<,>));
#>

// include file with transformation algorithms
<#@ include file="CsT4Ts.t4" #>

そして、あなたは出力を取得します

//CsT4Ts.Tests.PresetDTOBase => PresetBase
// CsT4Ts.Tests.PresetDTO => Preset
// CsT4Ts.Tests.TestInterface`2 => TestInterface
// CsT4Ts.Tests.TestEnum => TestEnum

declare class PresetBase
{
    PresetId: string;
    Title: string;
    InterviewDate: string;
}

declare class Preset extends PresetBase
{
    QuestionsIds: string[];
}

declare interface TestInterface<TA, TB>
{
    A: string;
    B: number;
    C: TestEnum;
    D: TestEnum[];
    E: number[];
    F: TA;
    G: TB[];
}

declare enum TestEnum
{
    Foo = 10,
    Boo = 100
}

ここで完全なソリューションを確認してください:https//bitbucket.org/chandrush/cst4ts


1

Bridge.netを使用することもできます。バージョン1.7以降、C#型のTypeScript定義の生成をサポートしています。http://bridge.net/docs/generate-typescript-definitions/を参照してください


主な問題は、グーグル検索を行うと、元の質問に
たどり着いて

ですから、カノニカルが最高の情報を持っていることを確認してください。複数の質問に投稿しないでください。この上の任意の更なる議論はに撮影することができますメタスタックオーバーフロー
マルタインピータース

1

@citykidの回答もとても気に入ったので、名前空間全体を一度に実行するように拡張しました。POCOクラスを名前空間に配置し、T4テンプレートを再構築するだけです。それぞれに個別のファイルを生成する方法を知っているといいのですが、それは世界の終わりではありません。

上部(クラスが必要な場所)の.DLLファイルを参照する必要があり、名前空間についても言及する必要があります。編集するすべての行はACMEでマークされています。@citykidへの主要な賞賛、感謝します!

<#@ template debug="true" hostSpecific="true" language="C#" #>
<#@ output extension=".ts" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ assembly name="$(TargetDir)YOUR_DLL_NAME_HERE_ACME.dll" #>
<#@ assembly name="$(TargetDir)YOUR_OTHER_DLL_NAME_HERE_ACME.dll" #>
<#@ assembly name="$(TargetDir)YOUR_OTHER_DLL_NAME_HERE_ACME.dll" #>
<#@ assembly name="$(TargetDir)YOUR_OTHER_DLL_NAME_HERE_ACME.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>

<#= Process("My.Very.Special.Namespace.ACME") #>
<#= Process("My.Other.Very.Special.Namespace.ACME") #>
<#= Process("My.Other.Very.Special.Namespace.ACME") #>
<#= Process("My.Other.Very.Special.Namespace.ACME") #>

<#+  

    List<Type> knownTypes = new List<Type>();

    string Process(string nameSpace) {
      var allass = AppDomain.CurrentDomain.GetAssemblies();
      var ss = "";
      foreach (var ass in allass)
      {
         ss += ProcessAssembly(ass, nameSpace);
      }
      return ss;
    }

   string ProcessAssembly(Assembly asm, string nameSpace) {
      try {
            Type[] types;
            try
            {
                types = asm.GetTypes();
            }
            catch (ReflectionTypeLoadException e)
            {
                types = e.Types;
            }
            var s = "";
            foreach (var t in types.Where(t => t != null))
            {
               try {

               if (String.Equals(t.Namespace, nameSpace, StringComparison.Ordinal))
               {
                    s += InterfaceOfType(t);
               }

               } catch (Exception e)
               {
               }
            }
            return s;      
      }
      catch (Exception ee2) {
        return "// ERROR LOADING TYPES: " + ee2;
      }

   }

    string InterfaceOfType(Type T)
    {   
        Type t = T;     
        var sb = new StringBuilder();
        sb.AppendFormat("interface {0} {{\r\n", t.Name);
        foreach (var mi in GetInterfaceMembers(t))
        {
            sb.AppendFormat("  {0}: {1};\r\n", this.ToCamelCase(mi.Name), GetTypeName(mi));
        }
        sb.AppendLine("}");
        knownTypes.Add(t);
        return sb.ToString();
    }

    string Interface<T>()
    {   
        Type t = typeof(T);     
        var sb = new StringBuilder();
        sb.AppendFormat("interface {0} {{\n", t.Name);
        foreach (var mi in GetInterfaceMembers(t))
        {
            sb.AppendFormat("  {0}: {1};\r\n", this.ToCamelCase(mi.Name), GetTypeName(mi));
        }
        sb.AppendLine("}");
        knownTypes.Add(t);
        return sb.ToString();
    }

    IEnumerable<MemberInfo> GetInterfaceMembers(Type type)
    {
        return type.GetMembers(BindingFlags.Public | BindingFlags.Instance)
            .Where(mi => mi.MemberType == MemberTypes.Field || mi.MemberType == MemberTypes.Property);
    }

    string ToCamelCase(string s)
    {
        if (string.IsNullOrEmpty(s)) return s;
        if (s.Length < 2) return s.ToLowerInvariant();
        return char.ToLowerInvariant(s[0]) + s.Substring(1);
    }

    string GetTypeName(MemberInfo mi)
    {
        Type t = (mi is PropertyInfo) ? ((PropertyInfo)mi).PropertyType : ((FieldInfo)mi).FieldType;
        return this.GetTypeName(t);
    }

    string GetTypeName(Type t)
    {
        if(t.IsPrimitive)
        {
            if (t == typeof(bool)) return "boolean";
            if (t == typeof(char)) return "string";
            return "number";
        }
        if (t == typeof(decimal)) return "number";            
        if (t == typeof(string)) return "string";
        if (t.IsArray)
        {            
            var at = t.GetElementType();
            return this.GetTypeName(at) + "[]";
        }
        if(typeof (System.Collections.IEnumerable).IsAssignableFrom(t)) 
        {
            var collectionType = t.GetGenericArguments()[0]; // all my enumerables are typed, so there is a generic argument
            return GetTypeName(collectionType) + "[]";
        }            
        if (Nullable.GetUnderlyingType(t) != null)
        {
            return this.GetTypeName(Nullable.GetUnderlyingType(t));
        }
        if(t.IsEnum) return "number";
        if(knownTypes.Contains(t)) return t.Name;
        return "any";
    }

    string Enums<T>() // Enums<>, since Enum<> is not allowed.
    {
        Type t = typeof(T);        
        var sb = new StringBuilder();        
        int[] values = (int[])Enum.GetValues(t);
        sb.AppendLine("var " + t.Name + " = {");
        foreach(var val in values) 
        {
            var name = Enum.GetName(typeof(T), val);
            sb.AppendFormat("{0}: {1},\r\n", name, val);
        }
        sb.AppendLine("}");
        return sb.ToString();
    }
#>

0

私の解決策は、単純にプロジェクトアセンブリ(および参照アセンブリ)を取得し、typescriptとc#間の相互作用に関係する型のスキャンを開始する小さなcodegen utilを記述することでした。このユーティリティは両方のjavascriptをd.tsとして出力します...ツールはビルド後のイベントで呼び出されます...チャームのように機能します!


なぜjsとd.tsを出力するように選択したのかわかりません。今のところ、単純に.tsを出力します。
Paul0515 2013年

1
こんにちはポール...あなたは私たちとutilコードを共有することができますか?あなたが言ったようなd.tsファイルではなく、(特定のフォルダーの場所に)tsファイルを作成するだけです。それはあなたのユーティリティができることですか?
Krishna Teja Veeramachaneni 2013

0

興味がある場合は、TypedRpcを使用できます。その目的は、TypeScriptでインターフェイスを作成することだけでなく、JsonRpcプロトコルを使用して.Netでサービスとのすべての通信を作成することです。

サーバーのクラスの例:

[TypedRpc.TypedRpcHandler]
public class RpcServerExample
{
    public String HelloWorld()
    {
        return "Hello World!";
    }
}

生成されたTypeScriptコードの使用:

/// <reference path="Scripts/TypedRpc.ts" />

let rpc: TypedRpc.RpcServerExample = new TypedRpc.RpcServerExample();

var callback = function(data, jsonResponse) {
    console.log(data);
};

rpc.HelloWorld().done(callback).fail(callback);

それを使用する方法の他の例については、https://github.com/Rodris/TypedRpcを確認してください


0

ASP.NET Web APIクライアントジェネレーターは、SDLC中にSwaggerツールチェーンやその他のものよりも便利でオーバーヘッドが少ない場合があります。

プログラマーは一般にWebApiClientGenを使用してクライアントAPIコードを生成しますが、このプロジェクトはPOCO2TS.exeも提供します。POCO2TS.exeは、POCOクラスからTypsScriptインターフェイスを生成するコマンドラインプログラムです。Poco2ts.exeまたはpoco2tsコンポーネントを使用して、コード生成をビルドパイプラインに統合できます。


0

node.jsで変換したい場合は、このパッケージ(csharp-to-typescript)を使用できます。 https://www.npmjs.com/package/csharp-to-typescript

sourcode:https : //github.com/YuvrajSagarRana/csharp-to-typescript

eg: 
// After installation, import the package.
var { CsharpToTs, getConfiguration } = require("csharp-to-typescript");

// Use CsharpToTs to convert your source code a. Method one give your source code as string:
const sourceCodeInString =   `public class Address
{
  public int Id {get; set;}
  public string Street { get; set; }
  public string City { get; set; }
}`

var outputTypescript = CsharpToTs(sourceCodeInString, getConfiguration());
console.log(outputTypescript);

// Output is

export class Address
{
  Id: number;
  Street: string;
  City: string;
}

0

VSCodeを使用している場合は、TypeScriptへの拡張C#を確認できます。

C#クラスをTypeScriptインターフェイスに変換する

クリック1つでC#コードから変換する方法をご覧ください。もちろん、ファクトリなどすべてのクラスが変換されるわけではありませんが、クライアント側にとっては十分です。データの形だけが必要です。ビジターパターンを使用する必要がある場合は、必要な追加のメソッドで装飾します。それをするのにほんの5秒しかかかりませんでした。上の1分と比べると、大きな勝利だと言えるでしょう。

私のブログ投稿で詳細をご覧ください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.