How to setup TypeLite to build types in other projects - typelite

I'm working in MS Dynamics CRM, and I have a WebResources project that contains all of my TypeScript. I have Plugin .net library dll that contains some POCO objects that will be returned via Rest to my javascript in my WebResources project. How do I setup TypeLite to build my Typescript files?
This is my assumption.
Install Typescript NuGet Package in my Plugin project
Decorate the POCO classes I need Typescript files for, with the [TsClass] attribute
Upon build, it will generate the Typescript Files to the Scripts folder that it will create in the Plugin project
I create a postbuild event that copies the Typescript files over to my WebResources Project
Is there an easier way?
Did I make an incorrect assumption?
Update
From Lukas's answer, I've updated my TypeLite.Net4.tt file to look like this:
<## template debug="false" hostspecific="True" language="C#" #>
<## assembly name="$(TargetDir)TypeLite.dll" #>
<## assembly name="$(TargetDir)TypeLite.Net4.dll" #>
<## assembly name="$(TargetDir)Xrm.Plugins.dll" #>
<## assembly name="$(TargetDir)$(TargetFileName)" #>
<## import namespace="TypeLite" #>
<## import namespace="TypeLite.Net4" #>
<##output extension=".d.ts"#>
<##include file="Manager.ttinclude"#>
<# var manager = Manager.Create(Host, GenerationEnvironment); #>
<# var ts = TypeScript.Definitions()
.WithReference("Enums.ts")
.For<Xrm.Plugins.Rest.Poco.AccountLookupResponse>();
#>
<#= ts.Generate(TsGeneratorOutput.Properties) #>
<# manager.StartNewFile("Enums.ts"); #>
<#= ts.Generate(TsGeneratorOutput.Enums) #>
<# manager.EndBlock(); #>
<# manager.Process(true); #>
This generates the correct definition in the TypeLite.Net4.d.ts file. I'm not currently using any enums in my class, so the Enums.ts is not necessary currently, but it doesn't hurt to have it.

There is another way, but I am not sure, whether it is better.
install TypeLITE.Lib package to your Plugin project (you need reference TypeLITE library there, because you want to use the [TsClass] attribute)
install TypeLITE package to your WebResources project and modify TypeLite.tt file to include a reference to your plugin.dll
<## assembly name="$(TargetDir)plugin.dll" #>
alternatively you can skip the first step and use fluent configuration TypeScript.Definitions().For<YourClass>() to include specific classes in the output file

Related

Referencing addins from secondary script file

I have a cake file with my Tasks defined.
I also have a second cake file with some classes defined.
In the second file, I would like to reference e.g. Cake.Json, and maybe Cake.Svn. But I cannot figure out how reference them.
How would I do that?
Both addins and utility Cake scripts are references using pre-processor directives.
Addin directive
Usage
#addin nuget:?package={NuGet Package Id}&version={NuGet package version}
Example:
#addin nuget:?package=Cake.Json&version=3.0.1
Reference directive
Usage
#r "Path to assembly / dll"
Example:
#r "bin/Cake.Json.dll"
Load directive
Usage
#load "Path to cake file"
Example:
#load "scripts/common.cake"
Reference
Read more about pre-processor directives at
https://cakebuild.net/docs/fundamentals/preprocessor-directives

MSBuild: How to Future-Proof Import Project Path?

A similar question was asked a few years ago, but I'm wondering if anything has changed in the interim or if folks have new ideas how to do this.
I've imported MSBuildTasks (MSBuild Community Tasks) as a Nuget package into a project within my solution. I can define a property for the path to the .targets file as follows:
<PropertyGroup>
<MSBuildTasks>$(SolutionDir)Packages\MSBuildTasks.1.5.0.235\tools\MSBuild.Community.Tasks.Targets</MSBuildTasks>
</PropertyGroup>
... and then import it using:
<Import Project="$(MSBuildTasks)"/>
Of course, I may choose to update the package at a later date in which case the folder name changes, so I'd prefer to avoid hard-coding the version number. One way I thought of to avoid this was to have a powershell script look for the latest version:
function Find-PackagePath
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)]$packagesPath,
[Parameter(Position=1,Mandatory=1)]$packageName
)
return (Get-ChildItem ($packagesPath + "\" + $packageName + "*")).FullName | Sort-Object $_ | select -Last 1
}
... and inject that as a command-line property for MSBuild:
msbuild $solutionFile "/p:Configuration=$buildConfiguration;Platform=$buildPlatform;MSBuildTasks=$MSBuildTasks";
I can confirm with a message that the injected path is indeed transmitted to my target:
<Target Name="_ReportMSBuildTasksPath" BeforeTargets="_ComputeSemanticVersion">
<Message Text="MSBUILDTASKS = $(MSBuildTasks)"/>
</Target>
... but if I try to import using the same import statement above, I get the following error message:
The value "" of the "Project" attribute in element <Import> is invalid. Parameter "path" cannot have zero length.
This is where I run out of ideas. How can I avoid hard-coding the version number in the tools path?
I found it strange that you need to manually import something.
MSBuildTasks NuGet package includes build\MSBuildTasks.targets. And Visual Studio should automatically add import of this file into your .csproj file.
And this import path is maintained by NuGet Package Manager in the Visual Studio.
So, you should just be able to use the tasks you need without importing anything manually.
If it does not work, then please check that .csproj file really includes autogenerated import to proper .targets file mentioned above.

How do I reference an assembly from the GAC in a PowerShell module?

I'm writing a PowerShell module which depending on the SMO assemblies in SQL Server. (The only one I need to reference is Microsoft.SqlServer.Smo.dll)
When I've been developing module. I've just taken a copy of the assembly I need and referenced it in my manifest file similar to this:
RequiredAssemblies = #(
"$env:userprofile\Documents\WindowsPowerShell\Modules\Dependencies\Microsoft.SqlServer.Smo.dll"
)
I would assume that in a production environment you'd want to reference assemblies from a standard location. I'd assume a standard location would be the GAC.
If I reference the assembly from the GAC, I get this, but this looks like it could break if a new version of the assembly is installed:
RequiredAssemblies = #(
'C:\WINDOWS\assembly\gac_msil\Microsoft.SqlServer.Smo\12.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.Smo.dll'
)
I could also reference the assembly directly from the SDK:
RequiredAssemblies = #(
'C:\Program Files\Microsoft SQL Server\120\SDK\Assemblies\Microsoft.SqlServer.Smo.dll'
)
Another option I've considered (but possibly might be breaking a EULA somewhere) is to copy the assemblies to a server share and reference that like so:
RequiredAssemblies = #(
'\\MyServer\PowerShellDependencies\Microsoft.SqlServer.Smo.dll'
)
But how should I be doing this?
If it's relevant, all computers that this module will be installed on are 64-bit and will have the SMO libraries installed. Also, this isn't a publicly available piece of software, it's being deployed on a company network.
Update: I've tried only specifying the name of the assembly in the manifest and this appears to work.
RequiredAssemblies = #(
'Microsoft.SqlServer.Smo.dll'
)
Unless you're going to deploy the SMO assemblies as private assemblies, then I wouldn't recommend loading them from direct references.
To load from the GAC, use the Add-Type cmdlet with the fully qualified assembly name...
Add-Type -AssemblyName "Microsoft.SqlServer.Smo, Version=12.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91"
Related:
How do I use Add-Type to load Microsoft.Web.Deployment?
You can also specify just the assembly without the version info:
Add-Type -AssemblyName "System.Xml.Linq"

Trouble Resolving Types from DomainModelTemplate

I am working on adding a base class to specific entities in my object model. To that end I have followed the samples in the following links:
http://drc.ideablade.com/devforce-2012/bin/view/Documentation/model-custom-base-class
http://drc.ideablade.com/devforce-2012/bin/view/Documentation/custom-code-generation-template
My *.tt file looks exactly like the example in the first link with the Assembly includes listed in the second link.
Currently I am getting two errors compiling the transformation:
Compiling transformation: The type or namespace name 'EntityOrComplexTypeWrapper' could not be found (are you missing a using directive or an assembly reference?)
Compiling transformation: The type or namespace name 'EntityTypeWrapper' could not be found (are you missing a using directive or an assembly reference?)
Can you provide any assistance resolving this matter?
So I dug into the IdeaBlade.VisualStudio.OM.CodeGenerator.EF5.dll using ildasm and was able to solve my problem by fully qualifying the objects' namespaces.
IdeaBlade.VisualStudio.OM.CodeGenerator.Metadata.EntityOrComplexTypeWrapper
IdeaBlade.VisualStudio.OM.CodeGenerator.Metadata.EntityTypeWrapper
I also had to add a few assembly imports to the header. Mine now looks like:
<## template language="C#" debug="true" hostSpecific="true" #>
<## output extension=".ReadMe" #>
<## Assembly Name="Microsoft.VisualStudio.TextTemplating.12.0" #>
<## Assembly Name="IdeaBlade.VisualStudio.OM.CodeGenerator.EF5.dll" #>
<## import namespace="IdeaBlade.VisualStudio.OM.CodeGenerator" #>
<## import namespace="IdeaBlade.VisualStudio.OM.CodeGenerator.Metadata" #>
<## Assembly Name="IdeaBlade.Core.dll" #>
<## import namespace="IdeaBlade.Core" #>
<## Assembly Name="IdeaBlade.EntityModel.Edm.Metadata.dll" #>
<## import namespace="IdeaBlade.EntityModel.Edm.Metadata" #>
The DevForce documentation was not complete for this feature.

Loading a NuGet assembly in T4 Template

I need to reference a Type in one of the assemblies referenced by the project containing my Visual Studio T4 template. However, the referenced assembly is installed from a NuGet package. As that Nuget reference evolves, so will the path that NuGet places it in within my solution's packages folder. For example, suppose my NuGet package is:
Facade.Contract.1.0.1-alpha
Then the relative path to it from my project is:
..\packages\Facade.Contract.1.0.1-alpha\lib\net4\Facade.Contract.dll
If the prerelease is updated to beta, that path will change. When the package is released, the path will change. And every time the path changes, the assembly line in my *.tt file is out of date:
<## assembly name="..\packages\Facade.Contract.1.0.1-alpha\lib\net4\Facade.Contract.dll" #>
I don't think there's a way to accomplish this directly with the assembly directive; however, I'm open to some crazy ideas. Could I load the assembly myself into the current, or a subordinate or reflection-only AppDomain?
I think I could, but I'm not sure how to go about dynamically discovering the path to the referenced assembly in the project's references using T4 logic.
Any ideas?
I've found a solution using VSLangProject as suggested by this article: http://t4-editor.tangible-engineering.com/blog/add-references-to-visual-studio-project-from-t4-template.html
Given a string serviceContractReferenceAssembly a to identify the name of the reference assembly in my containing project, and serviceContractReferenceType to identify the type within that assembly, the following worked:
var templateItem = dte.Solution.FindProjectItem(this.Host.TemplateFile);
var project = templateItem.ContainingProject;
var vsProject = project.Object as VSLangProj.VSProject;
foreach(var referenceObj in vsProject.References)
{
var reference = (VSLangProj.Reference)referenceObj;
if(reference.Name != serviceContractReferenceAssembly) continue;
var serviceContractAssembly = Assembly.LoadFile(reference.Path);
var serviceContractType = serviceContractAssembly.GetType(serviceContractReferenceType);
// Do something with it here
}
The Nuget team has made an extension available that allows you some control over the packages in a solution/project. So if you have control over the environment and can be sure everyone has this installed you might be able to search for the installed packages and then dynamically load them during your T4 execution. Since these Nuget assemblies are already complied and not part of your solution/project I would think using the standard Assembly.Load would work but you would need to test that.