├── .gitignore
├── LICENSE
├── README.md
├── SignalrTypescriptGenerator.sln
├── icon.png
└── src
└── SignalrTypescriptGenerator
├── App.config
├── Models
├── ClientInfo.cs
├── CommandLineOptions.cs
├── DataContractInfo.cs
├── EnumInfo.cs
├── FunctionDetails.cs
├── ServiceInfo.cs
├── TypeInfo.cs
└── TypesModel.cs
├── Program.cs
├── Properties
└── AssemblyInfo.cs
├── SignalrHubinator.cs
├── SignalrTypescriptGenerator.csproj
├── SignalrTypescriptGenerator.nuspec
├── TypeHelper.cs
├── build-nuget.ps1
├── packages.config
└── template.cshtml
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 |
24 | # Visual Studio 2015 cache/options directory
25 | .vs/
26 | # Uncomment if you have tasks that create the project's static files in wwwroot
27 | #wwwroot/
28 |
29 | # MSTest test Results
30 | [Tt]est[Rr]esult*/
31 | [Bb]uild[Ll]og.*
32 |
33 | # NUNIT
34 | *.VisualState.xml
35 | TestResult.xml
36 |
37 | # Build Results of an ATL Project
38 | [Dd]ebugPS/
39 | [Rr]eleasePS/
40 | dlldata.c
41 |
42 | # DNX
43 | project.lock.json
44 | artifacts/
45 |
46 | *_i.c
47 | *_p.c
48 | *_i.h
49 | *.ilk
50 | *.meta
51 | *.obj
52 | *.pch
53 | *.pdb
54 | *.pgc
55 | *.pgd
56 | *.rsp
57 | *.sbr
58 | *.tlb
59 | *.tli
60 | *.tlh
61 | *.tmp
62 | *.tmp_proj
63 | *.log
64 | *.vspscc
65 | *.vssscc
66 | .builds
67 | *.pidb
68 | *.svclog
69 | *.scc
70 |
71 | # Chutzpah Test files
72 | _Chutzpah*
73 |
74 | # Visual C++ cache files
75 | ipch/
76 | *.aps
77 | *.ncb
78 | *.opendb
79 | *.opensdf
80 | *.sdf
81 | *.cachefile
82 |
83 | # Visual Studio profiler
84 | *.psess
85 | *.vsp
86 | *.vspx
87 | *.sap
88 |
89 | # TFS 2012 Local Workspace
90 | $tf/
91 |
92 | # Guidance Automation Toolkit
93 | *.gpState
94 |
95 | # ReSharper is a .NET coding add-in
96 | _ReSharper*/
97 | *.[Rr]e[Ss]harper
98 | *.DotSettings.user
99 |
100 | # JustCode is a .NET coding add-in
101 | .JustCode
102 |
103 | # TeamCity is a build add-in
104 | _TeamCity*
105 |
106 | # DotCover is a Code Coverage Tool
107 | *.dotCover
108 |
109 | # NCrunch
110 | _NCrunch_*
111 | .*crunch*.local.xml
112 | nCrunchTemp_*
113 |
114 | # MightyMoose
115 | *.mm.*
116 | AutoTest.Net/
117 |
118 | # Web workbench (sass)
119 | .sass-cache/
120 |
121 | # Installshield output folder
122 | [Ee]xpress/
123 |
124 | # DocProject is a documentation generator add-in
125 | DocProject/buildhelp/
126 | DocProject/Help/*.HxT
127 | DocProject/Help/*.HxC
128 | DocProject/Help/*.hhc
129 | DocProject/Help/*.hhk
130 | DocProject/Help/*.hhp
131 | DocProject/Help/Html2
132 | DocProject/Help/html
133 |
134 | # Click-Once directory
135 | publish/
136 |
137 | # Publish Web Output
138 | *.[Pp]ublish.xml
139 | *.azurePubxml
140 | # TODO: Comment the next line if you want to checkin your web deploy settings
141 | # but database connection strings (with potential passwords) will be unencrypted
142 | *.pubxml
143 | *.publishproj
144 |
145 | # NuGet Packages
146 | *.nupkg
147 | # The packages folder can be ignored because of Package Restore
148 | **/packages/*
149 | # except build/, which is used as an MSBuild target.
150 | !**/packages/build/
151 | # Uncomment if necessary however generally it will be regenerated when needed
152 | #!**/packages/repositories.config
153 | # NuGet v3's project.json files produces more ignoreable files
154 | *.nuget.props
155 | *.nuget.targets
156 |
157 | # Microsoft Azure Build Output
158 | csx/
159 | *.build.csdef
160 |
161 | # Microsoft Azure Emulator
162 | ecf/
163 | rcf/
164 |
165 | # Microsoft Azure ApplicationInsights config file
166 | ApplicationInsights.config
167 |
168 | # Windows Store app package directory
169 | AppPackages/
170 | BundleArtifacts/
171 |
172 | # Visual Studio cache files
173 | # files ending in .cache can be ignored
174 | *.[Cc]ache
175 | # but keep track of directories ending in .cache
176 | !*.[Cc]ache/
177 |
178 | # Others
179 | ClientBin/
180 | ~$*
181 | *~
182 | *.dbmdl
183 | *.dbproj.schemaview
184 | *.pfx
185 | *.publishsettings
186 | node_modules/
187 | orleans.codegen.cs
188 |
189 | # RIA/Silverlight projects
190 | Generated_Code/
191 |
192 | # Backup & report files from converting an old project file
193 | # to a newer Visual Studio version. Backup files are not needed,
194 | # because we have git ;-)
195 | _UpgradeReport_Files/
196 | Backup*/
197 | UpgradeLog*.XML
198 | UpgradeLog*.htm
199 |
200 | # SQL Server files
201 | *.mdf
202 | *.ldf
203 |
204 | # Business Intelligence projects
205 | *.rdl.data
206 | *.bim.layout
207 | *.bim_*.settings
208 |
209 | # Microsoft Fakes
210 | FakesAssemblies/
211 |
212 | # GhostDoc plugin setting file
213 | *.GhostDoc.xml
214 |
215 | # Node.js Tools for Visual Studio
216 | .ntvs_analysis.dat
217 |
218 | # Visual Studio 6 build log
219 | *.plg
220 |
221 | # Visual Studio 6 workspace options file
222 | *.opt
223 |
224 | # Visual Studio LightSwitch build output
225 | **/*.HTMLClient/GeneratedArtifacts
226 | **/*.DesktopClient/GeneratedArtifacts
227 | **/*.DesktopClient/ModelManifest.xml
228 | **/*.Server/GeneratedArtifacts
229 | **/*.Server/ModelManifest.xml
230 | _Pvt_Extensions
231 |
232 | # Paket dependency manager
233 | .paket/paket.exe
234 |
235 | # FAKE - F# Make
236 | .fake/
237 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Chris S.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.nuget.org/packages/SignalrTypescriptGenerator)
2 |
3 | # SignalrTypescriptGenerator
4 | A command line tool for generating typescript definitions for Signalr
5 |
6 | This tool is based off this gist: https://gist.github.com/robfe/4583549. It works using the same C# logic, but skips the need for a T4 template which can be fiddly to get working on build servers.
7 |
8 | ### Nuget
9 |
10 | install-package SignalrTypescriptGenerator
11 |
12 | ### Usage
13 |
14 | .\SignalrTypescriptGenerator.exe -a "c:\etc\path-to-myassembly.dll"
15 |
16 | This will print the Typescript to the console window. You can write to a file, which automatically checks if the file has changed:
17 |
18 | .\SignalrTypescriptGenerator.exe -a "c:\etc\path-to-myassembly.dll" -o "C:\temp\.myfile.d.ts"
19 |
20 | If you don't specify an output file, the typescript output is written to the console window. A post-build command line in Visual Studio might look like this:
21 |
22 | $(SolutionDir)\packages\SignalrTypescriptGenerator.1.0.11\tools\SignalrTypescriptGenerator.exe -a "$(TargetPath)" -o "$(SolutionDir)src\MyProject.Web\Scripts\typings\Hubs.d.ts"
--------------------------------------------------------------------------------
/SignalrTypescriptGenerator.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.24720.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalrTypescriptGenerator", "src\SignalrTypescriptGenerator\SignalrTypescriptGenerator.csproj", "{C90F8C7B-213B-4CD0-A9F0-3A39634CECDE}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {C90F8C7B-213B-4CD0-A9F0-3A39634CECDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {C90F8C7B-213B-4CD0-A9F0-3A39634CECDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {C90F8C7B-213B-4CD0-A9F0-3A39634CECDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {C90F8C7B-213B-4CD0-A9F0-3A39634CECDE}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yetanotherchris/SignalrTypescriptGenerator/786551ac85b18443ee5463da5a6d1db9f2ba3af0/icon.png
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/Models/ClientInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace SignalrTypescriptGenerator.Models
4 | {
5 | public class ClientInfo
6 | {
7 | public string ModuleName { get; set; }
8 | public string InterfaceName { get; set; }
9 | public List FunctionDetails { get; set; }
10 |
11 | public ClientInfo()
12 | {
13 | FunctionDetails = new List();
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/Models/CommandLineOptions.cs:
--------------------------------------------------------------------------------
1 | using CommandLine;
2 |
3 | namespace SignalrTypescriptGenerator.Models
4 | {
5 | public class CommandLineOptions
6 | {
7 | [Option('a', "assembly", HelpText = "The path to the assembly (.dll/.exe)", Required = true)]
8 | public string AssemblyPath { get; set; }
9 |
10 | [Option('o', "outfile", HelpText = "The path to the file to generate. If this is empty, the output is written to stdout.")]
11 | public string OutFile { get; set; }
12 | }
13 | }
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/Models/DataContractInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace SignalrTypescriptGenerator.Models
4 | {
5 | public class DataContractInfo
6 | {
7 | public string ModuleName { get; set; }
8 | public string InterfaceName { get; set; }
9 | public List Properties { get; set; }
10 |
11 | public DataContractInfo()
12 | {
13 | Properties = new List();
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/Models/EnumInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace SignalrTypescriptGenerator.Models
4 | {
5 | public class EnumInfo
6 | {
7 | public string ModuleName { get; set; }
8 | public string InterfaceName { get; set; }
9 | public List Properties { get; set; }
10 |
11 | public EnumInfo()
12 | {
13 | Properties = new List();
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/Models/FunctionDetails.cs:
--------------------------------------------------------------------------------
1 | namespace SignalrTypescriptGenerator.Models
2 | {
3 | public class FunctionDetails
4 | {
5 | public string Name { get; set; }
6 | public string Arguments { get; set; }
7 | public string ReturnType { get; set; }
8 | }
9 | }
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/Models/ServiceInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace SignalrTypescriptGenerator.Models
4 | {
5 | public class ServiceInfo
6 | {
7 | public string ModuleName { get; set; }
8 | public string InterfaceName { get; set; }
9 | public string ClientType { get; set; }
10 |
11 | public string ServerType { get; set; }
12 | public string ServerTypeFullNamespace { get; set; }
13 | public List ServerFunctions { get; set; }
14 |
15 | public ServiceInfo()
16 | {
17 | ServerFunctions = new List();
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/Models/TypeInfo.cs:
--------------------------------------------------------------------------------
1 | namespace SignalrTypescriptGenerator.Models
2 | {
3 | public class TypeInfo
4 | {
5 | public string Name { get; set; }
6 | public string TypescriptType { get; set; }
7 | }
8 | }
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/Models/TypesModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace SignalrTypescriptGenerator.Models
5 | {
6 | public class TypesModel
7 | {
8 | public List Hubs { get; set; }
9 | public List ServiceContracts { get; set; }
10 | public List Clients { get; set; }
11 | public List DataContracts { get; set; }
12 | public List Enums { get; set; }
13 |
14 | public string LastGenerated
15 | {
16 | get
17 | {
18 | return $"// Autogenerated by SignalrTypescriptGenerator.exe at {DateTime.Now}";
19 | }
20 | }
21 |
22 | public TypesModel()
23 | {
24 | Hubs = new List();
25 | ServiceContracts = new List();
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Security.Cryptography;
6 | using System.Text;
7 | using CommandLine;
8 | using RazorEngine;
9 | using RazorEngine.Templating;
10 | using SignalrTypescriptGenerator.Models;
11 | using Encoding = System.Text.Encoding;
12 |
13 | namespace SignalrTypescriptGenerator
14 | {
15 | class Program
16 | {
17 | static int Main(string[] args)
18 | {
19 | if (AppDomain.CurrentDomain.IsDefaultAppDomain())
20 | {
21 | return RunInNewAppDomainToAllowRazorEngineToCleanup(args);
22 | }
23 |
24 | try
25 | {
26 | return Parser.Default.ParseArguments(args)
27 | .MapResult(options =>
28 | {
29 | Run(options);
30 | return 0;
31 | },
32 | errors => 1);
33 | }
34 | catch (Exception e)
35 | {
36 | Console.WriteLine(e);
37 | return 1;
38 | }
39 | }
40 |
41 | static int RunInNewAppDomainToAllowRazorEngineToCleanup(string[] args)
42 | {
43 | var appDomain = AppDomain.CreateDomain("RazorEngine", null, AppDomain.CurrentDomain.SetupInformation);
44 | var exitCode = appDomain.ExecuteAssembly(Assembly.GetExecutingAssembly().Location, args);
45 | AppDomain.Unload(appDomain);
46 | return exitCode;
47 | }
48 |
49 | static void Run(CommandLineOptions commandLineOptions)
50 | {
51 | var signalrHelper = new SignalrHubinator(commandLineOptions.AssemblyPath);
52 |
53 | var model = new TypesModel();
54 | model.Hubs = signalrHelper.GetHubs();
55 | model.ServiceContracts = signalrHelper.GetServiceContracts();
56 | model.Clients = signalrHelper.GetClients();
57 | model.DataContracts = signalrHelper.GetDataContracts();
58 | model.Enums = signalrHelper.GetEnums();
59 |
60 | string template = ReadEmbeddedFile("template.cshtml");
61 | string outputText = Engine.Razor.RunCompile(template, "templateKey", null, model);
62 |
63 | if (!string.IsNullOrEmpty(commandLineOptions.OutFile))
64 | {
65 | if (FileHasChanged(commandLineOptions.OutFile, outputText))
66 | {
67 | outputText = model.LastGenerated + Environment.NewLine + outputText;
68 | File.WriteAllText(commandLineOptions.OutFile, outputText);
69 | }
70 | }
71 | else
72 | {
73 | outputText = model.LastGenerated + Environment.NewLine + outputText;
74 | Console.WriteLine(outputText);
75 | }
76 | }
77 |
78 | static bool FileHasChanged(string filename, string contents)
79 | {
80 | string currentContents = File.Exists(filename) ? File.ReadAllText(filename) : string.Empty;
81 |
82 | // Remove the timestamp
83 | int startIndex = currentContents.IndexOf("// Autogenerated", StringComparison.Ordinal);
84 | if (startIndex > -1)
85 | {
86 | int endIndex = currentContents.IndexOf(Environment.NewLine, startIndex, StringComparison.Ordinal);
87 | if (endIndex > startIndex)
88 | {
89 | currentContents = currentContents.Substring(endIndex + Environment.NewLine.Length);
90 | }
91 | }
92 |
93 | string currentHash = GetMd5(currentContents);
94 | string newHash = GetMd5(contents);
95 | Console.WriteLine("[SignalrTypescriptGenerator] Existing MD5 for {0}: {1}", filename, currentHash);
96 | Console.WriteLine("[SignalrTypescriptGenerator] New MD5: {0}", newHash);
97 |
98 | bool hashesAreDifferent = (currentHash != newHash);
99 | Console.WriteLine("[SignalrTypescriptGenerator] (content is {0})", hashesAreDifferent ? "different - generating new file" : "the same - skipping file generation.");
100 |
101 | return hashesAreDifferent;
102 | }
103 |
104 | static string GetMd5(string contents)
105 | {
106 | using (var md5 = MD5.Create())
107 | {
108 | using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(contents)))
109 | {
110 | var hash = md5.ComputeHash(memoryStream);
111 |
112 | StringBuilder result = new StringBuilder();
113 | foreach (byte b in hash)
114 | result = result.Append(b.ToString("x2"));
115 |
116 | return result.ToString();
117 | }
118 | }
119 | }
120 |
121 | static string ReadEmbeddedFile(string file)
122 | {
123 | string resourcePath = string.Format("{0}.{1}", typeof(Program).Namespace, file);
124 |
125 | Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourcePath);
126 | if (stream == null)
127 | throw new InvalidOperationException(string.Format("Unable to find '{0}' as an embedded resource", resourcePath));
128 |
129 | string textContent = "";
130 | using (StreamReader reader = new StreamReader(stream))
131 | {
132 | textContent = reader.ReadToEnd();
133 | }
134 |
135 | return textContent;
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("SignalrTypescriptGenerator")]
9 | [assembly: AssemblyDescription("Command line tool for generating Typescript hub definitions for a Signalr assembly.")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("C.Small")]
12 | [assembly: AssemblyProduct("SignalrTypescriptGenerator")]
13 | [assembly: AssemblyCopyright("Copyright © C.Small 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("c90f8c7b-213b-4cd0-a9f0-3a39634cecde")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.13.0")]
36 | [assembly: AssemblyFileVersion("1.0.13.0")]
37 |
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/SignalrHubinator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Reflection;
6 | using Microsoft.AspNet.SignalR;
7 | using Microsoft.AspNet.SignalR.Hubs;
8 | using SignalrTypescriptGenerator.Models;
9 | using TypeInfo = SignalrTypescriptGenerator.Models.TypeInfo;
10 |
11 | namespace SignalrTypescriptGenerator
12 | {
13 | internal class SignalrHubinator
14 | {
15 | private static string _assemblyRootFolder;
16 | private readonly TypeHelper _typeHelper;
17 | private DefaultHubManager _hubmanager;
18 |
19 | public SignalrHubinator(string assemblyPath)
20 | {
21 | _assemblyRootFolder = Path.GetDirectoryName(assemblyPath);
22 | LoadAssemblyIntoAppDomain(assemblyPath);
23 |
24 | _typeHelper = new TypeHelper();
25 |
26 | var defaultDependencyResolver = new DefaultDependencyResolver();
27 | _hubmanager = new DefaultHubManager(defaultDependencyResolver);
28 | }
29 |
30 | public TypeHelper TypeHelper
31 | {
32 | get { return _typeHelper; }
33 | }
34 |
35 | private static Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)
36 | {
37 | string assemblyPath = Path.Combine(_assemblyRootFolder, new AssemblyName(args.Name).Name + ".dll");
38 | if (File.Exists(assemblyPath) == false)
39 | return null;
40 |
41 | Assembly assembly = Assembly.LoadFrom(assemblyPath);
42 | return assembly;
43 | }
44 |
45 | private void LoadAssemblyIntoAppDomain(string assemblyPath)
46 | {
47 | AppDomain currentDomain = AppDomain.CurrentDomain;
48 | currentDomain.AssemblyResolve += new ResolveEventHandler(LoadFromSameFolder);
49 | Assembly.LoadFile(assemblyPath);
50 | }
51 |
52 | public List GetHubs()
53 | {
54 | var items = new List();
55 | foreach (var hub in _hubmanager.GetHubs())
56 | {
57 | string name = hub.NameSpecified ? hub.Name : _typeHelper.FirstCharLowered(hub.Name);
58 | string typename = hub.HubType.FullName;
59 |
60 | items.Add(new TypeInfo() { Name = name, TypescriptType = typename });
61 | }
62 |
63 | return items;
64 | }
65 |
66 | public List GetServiceContracts()
67 | {
68 | var list = new List();
69 | var serviceInfo = new ServiceInfo();
70 |
71 | foreach (var hub in _hubmanager.GetHubs())
72 | {
73 | Type hubType = hub.HubType;
74 |
75 | string moduleName = hubType.Namespace;
76 | string interfaceName = hubType.Name;
77 | serviceInfo.ModuleName = moduleName;
78 | serviceInfo.InterfaceName = interfaceName;
79 |
80 | Type clientType = TypeHelper.ClientType(hubType);
81 | string clientTypeName = clientType != null ? clientType.FullName : "any";
82 | serviceInfo.ClientType = clientTypeName;
83 |
84 | // Server type and functions
85 | string serverType = hubType.Name + "Server";
86 | string serverFullNamespace = hubType.FullName + "Server";
87 | serviceInfo.ServerType = serverType;
88 | serviceInfo.ServerTypeFullNamespace = serverFullNamespace;
89 | foreach (var method in _hubmanager.GetHubMethods(hub.Name))
90 | {
91 | var ps = method.Parameters.Select(x => x.Name + " : " + TypeHelper.GetTypeContractName(x.ParameterType));
92 | var functionDetails = new FunctionDetails()
93 | {
94 | Name = _typeHelper.FirstCharLowered(method.Name),
95 | Arguments = "(" + string.Join(", ", ps) + ")",
96 | ReturnType = "JQueryPromise<" +TypeHelper.GetTypeContractName(method.ReturnType)+ ">"
97 | };
98 |
99 | serviceInfo.ServerFunctions.Add(functionDetails);
100 | }
101 |
102 | list.Add(serviceInfo);
103 | }
104 |
105 | return list;
106 | }
107 |
108 | public List GetClients()
109 | {
110 | var list = new List();
111 |
112 | foreach (var hub in _hubmanager.GetHubs())
113 | {
114 | Type hubType = hub.HubType;
115 | Type clientType = TypeHelper.ClientType(hubType);
116 |
117 | if (clientType != null)
118 | {
119 | string moduleName = clientType.Namespace;
120 | string interfaceName = clientType.Name;
121 | var clientInfo = new ClientInfo();
122 |
123 | clientInfo.ModuleName = moduleName;
124 | clientInfo.InterfaceName = interfaceName;
125 | clientInfo.FunctionDetails = TypeHelper.GetClientFunctions(hubType);
126 | list.Add(clientInfo);
127 | }
128 | }
129 |
130 | return list;
131 | }
132 |
133 | public List GetDataContracts()
134 | {
135 | var list = new List();
136 |
137 | while (_typeHelper.InterfaceTypes.Count != 0)
138 | {
139 | var type = _typeHelper.InterfaceTypes.Pop();
140 | var dataContractInfo = new DataContractInfo();
141 |
142 | string moduleName = type.Namespace;
143 | string interfaceName = _typeHelper.GenericSpecificName(type, false);
144 |
145 | dataContractInfo.ModuleName = moduleName;
146 | dataContractInfo.InterfaceName = interfaceName;
147 |
148 | foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
149 | {
150 | string propertyName = property.Name;
151 | string typeName = _typeHelper.GetTypeContractName(property.PropertyType);
152 |
153 | dataContractInfo.Properties.Add(new TypeInfo() { Name = propertyName, TypescriptType = typeName });
154 | }
155 |
156 | list.Add(dataContractInfo);
157 | }
158 |
159 | return list;
160 | }
161 |
162 | public List GetEnums()
163 | {
164 | var list = new List();
165 |
166 | while (_typeHelper.EnumTypes.Count != 0)
167 | {
168 | var type = _typeHelper.EnumTypes.Pop();
169 | var enuminfo = new EnumInfo();
170 |
171 | string moduleName = type.Namespace;
172 | string interfaceName = _typeHelper.GenericSpecificName(type, false);
173 |
174 | enuminfo.ModuleName = moduleName;
175 | enuminfo.InterfaceName = interfaceName;
176 |
177 | foreach (string name in Enum.GetNames(type))
178 | {
179 | string propertyName = name;
180 | string typeName = string.Format("{0:D}", Enum.Parse(type, name));
181 |
182 | enuminfo.Properties.Add(new TypeInfo() { Name = propertyName, TypescriptType = typeName });
183 | }
184 |
185 | list.Add(enuminfo);
186 | }
187 |
188 | return list;
189 | }
190 | }
191 | }
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/SignalrTypescriptGenerator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C90F8C7B-213B-4CD0-A9F0-3A39634CECDE}
8 | Exe
9 | Properties
10 | SignalrTypescriptGenerator
11 | SignalrTypescriptGenerator
12 | v4.5.1
13 | 512
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 | ..\..\packages\CommandLineParser.2.0.275-beta\lib\net45\CommandLine.dll
38 | True
39 |
40 |
41 | ..\..\packages\Microsoft.AspNet.SignalR.Core.2.2.0\lib\net45\Microsoft.AspNet.SignalR.Core.dll
42 | True
43 |
44 |
45 | ..\..\packages\Microsoft.Owin.2.1.0\lib\net45\Microsoft.Owin.dll
46 | True
47 |
48 |
49 | ..\..\packages\Microsoft.Owin.Security.2.1.0\lib\net45\Microsoft.Owin.Security.dll
50 | True
51 |
52 |
53 | ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll
54 | True
55 |
56 |
57 | ..\..\packages\Owin.1.0\lib\net40\Owin.dll
58 | True
59 |
60 |
61 | ..\..\packages\RazorEngine.3.7.7\lib\net45\RazorEngine.dll
62 | True
63 |
64 |
65 |
66 |
67 | ..\..\packages\Microsoft.AspNet.Razor.3.0.0\lib\net45\System.Web.Razor.dll
68 | True
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
108 |
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/SignalrTypescriptGenerator.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SignalrTypescriptGenerator
5 | $version$
6 | Signalr Typescript Hub Generator
7 | C.Small
8 | >C.Small
9 | https://github.com/yetanotherchris/SignalrTypescriptGenerator
10 | https://raw.githubusercontent.com/yetanotherchris/SignalrTypescriptGenerator/master/icon.png
11 | false
12 | Command line tool for generating Typescript hub definitions for a Signalr assembly.
13 | Breaking change: now use -a for the assembly, and -o for the file to write. See the Github project page for examples.
14 | C.Small Copyright 2016
15 | typescript signalr hubs
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/TypeHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text.RegularExpressions;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNet.SignalR;
7 | using SignalrTypescriptGenerator.Models;
8 |
9 | namespace SignalrTypescriptGenerator
10 | {
11 | internal class TypeHelper
12 | {
13 | private readonly HashSet _doneTypes;
14 | public readonly Stack InterfaceTypes;
15 | public readonly Stack EnumTypes;
16 |
17 | public TypeHelper()
18 | {
19 | _doneTypes = new HashSet();
20 | InterfaceTypes = new Stack();
21 | EnumTypes = new Stack();
22 | }
23 |
24 | public List GetClientFunctions(Type hubType)
25 | {
26 | var list = new List();
27 |
28 | Type clientType = ClientType(hubType);
29 | if (clientType != null)
30 | {
31 | foreach (var method in clientType.GetMethods())
32 | {
33 | var functionDetails = new FunctionDetails();
34 | IEnumerable ps = method.GetParameters().Select(x => x.Name + " : " + GetTypeContractName(x.ParameterType));
35 | string functionName = FirstCharLowered(method.Name);
36 | string functionArgs = "(" + string.Join(", ", ps) + ")";
37 |
38 | functionDetails.Name = functionName;
39 | functionDetails.Arguments = functionArgs;
40 |
41 | list.Add(functionDetails);
42 | }
43 | }
44 |
45 | return list;
46 | }
47 |
48 | public string FirstCharLowered(string s)
49 | {
50 | return Regex.Replace(s, "^.", x => x.Value.ToLowerInvariant());
51 | }
52 |
53 | public Type ClientType(Type hubType)
54 | {
55 | while (hubType != null && hubType != typeof(Hub))
56 | {
57 | if (hubType.IsGenericType && hubType.GetGenericTypeDefinition() == typeof(Hub<>))
58 | {
59 | return hubType.GetGenericArguments().Single();
60 | }
61 | hubType = hubType.BaseType;
62 | }
63 | return null;
64 | }
65 |
66 | public string GetTypeContractName(Type type)
67 | {
68 | if (type == typeof(Task))
69 | {
70 | return "void";
71 | }
72 |
73 | if (type.IsArray)
74 | {
75 | return GetTypeContractName(type.GetElementType()) + "[]";
76 | }
77 |
78 | if (type.IsGenericType)
79 | {
80 | if (typeof(Task<>).IsAssignableFrom(type.GetGenericTypeDefinition()))
81 | {
82 | return GetTypeContractName(type.GetGenericArguments()[0]);
83 | }
84 |
85 | if (typeof(Nullable<>).IsAssignableFrom(type.GetGenericTypeDefinition()))
86 | {
87 | return GetTypeContractName(type.GetGenericArguments()[0]);
88 | }
89 |
90 | if (typeof(List<>).IsAssignableFrom(type.GetGenericTypeDefinition()))
91 | {
92 | return GetTypeContractName(type.GetGenericArguments()[0]) + "[]";
93 | }
94 | }
95 |
96 | switch (type.Name.ToLowerInvariant())
97 | {
98 |
99 | case "datetime":
100 | return "Date";
101 | case "int16":
102 | case "int32":
103 | case "int64":
104 | case "single":
105 | case "double":
106 | return "number";
107 | case "boolean":
108 | return "boolean";
109 | case "void":
110 | case "string":
111 | return type.Name.ToLowerInvariant();
112 | }
113 |
114 | if (!_doneTypes.Contains(type))
115 | {
116 | _doneTypes.Add(type);
117 | if (type.IsEnum)
118 | {
119 | EnumTypes.Push(type);
120 | }
121 | else
122 | {
123 | InterfaceTypes.Push(type);
124 | }
125 | }
126 | return GenericSpecificName(type, true);
127 | }
128 |
129 | public string GenericSpecificName(Type type, bool referencing)
130 | {
131 | string name = (referencing ? type.FullName : type.Name).Split('`').First();
132 | if (type.IsGenericType)
133 | {
134 | name += "_" + string.Join("_", type.GenericTypeArguments.Select(a => GenericSpecificName(a, false))) + "_";
135 | }
136 | return name;
137 | }
138 | }
139 | }
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/build-nuget.ps1:
--------------------------------------------------------------------------------
1 | # This could be automated via appveyor
2 | Write-Host "Make sure you have updated the assemblyinfo file and compiled in release mode first."
3 | $version = Read-Host "What is the version number?"
4 | $apikey = Read-Host "Enter a nuget.org API key"
5 |
6 | nuget pack .\SignalrTypescriptGenerator.nuspec -Prop Configuration=Release -Version $version
7 | nuget push ".\SignalrTypescriptGenerator.$version.nupkg" $apikey -Source https://www.nuget.org/api/v2/package
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/SignalrTypescriptGenerator/template.cshtml:
--------------------------------------------------------------------------------
1 | @using System
2 | @using SignalrTypescriptGenerator.Models
3 | @*Model is a TypesModel*@
4 | // Get signalr.d.ts.ts from https://github.com/borisyankov/DefinitelyTyped (or delete the reference)
5 | ///
6 | ///
7 |
8 | // Hubs
9 | interface SignalR
10 | {
11 | @foreach (TypeInfo type in Model.Hubs)
12 | {
13 | @(type.Name) : @(type.TypescriptType);
14 | }
15 | }
16 |
17 | // Service contracts
18 | @foreach (ServiceInfo serviceInfo in Model.ServiceContracts){
19 |
20 | declare module @serviceInfo.ModuleName
21 | {
22 |
23 | interface @serviceInfo.InterfaceName
24 | {
25 | server : @Raw(serviceInfo.ServerTypeFullNamespace);
26 | client : @Raw(serviceInfo.ClientType);
27 | }
28 |
29 | interface @serviceInfo.ServerType
30 | {
31 | @foreach (FunctionDetails functionDetails in serviceInfo.ServerFunctions)
32 | {
33 | @Raw(functionDetails.Name + functionDetails.Arguments) : @Raw(functionDetails.ReturnType);
34 | }
35 | }
36 | }
37 |
38 | }
39 |
40 | // Clients
41 | @foreach (ClientInfo clientInfo in Model.Clients){
42 |
43 | declare module @clientInfo.ModuleName
44 | {
45 | interface @clientInfo.InterfaceName
46 | {
47 | @foreach (FunctionDetails functionDetails in clientInfo.FunctionDetails)
48 | {
49 | @Raw(functionDetails.Name) : @Raw(functionDetails.Arguments) => void;
50 | }
51 | }
52 | }
53 |
54 | }
55 |
56 | // Data contracts
57 | @foreach (DataContractInfo dataContractInfo in Model.DataContracts){
58 |
59 | declare module @dataContractInfo.ModuleName
60 | {
61 | interface @dataContractInfo.InterfaceName
62 | {
63 | @foreach (TypeInfo property in dataContractInfo.Properties)
64 | {
65 | @Raw(property.Name) : @Raw(property.TypescriptType);
66 | }
67 | }
68 | }
69 |
70 | }
71 |
72 | // Enums
73 | @foreach (EnumInfo enumInfo in Model.Enums){
74 |
75 | declare module @enumInfo.ModuleName
76 | {
77 | enum @enumInfo.InterfaceName
78 | {
79 | @foreach (TypeInfo property in enumInfo.Properties)
80 | {
81 | @Raw(property.Name) = @Raw(property.TypescriptType),
82 | }
83 | }
84 | }
85 |
86 | }
--------------------------------------------------------------------------------