How do I manage generated classes in a Visual Studio solution? - visual-studio

I have written a code generator using CodeDom and it generates a number of classes from stored procedures. I'd like to add its execution as a build step and then add all of its classes to the solution programatically at build-time.
How do I do this?

Use Custom Build Providers
Subsonic also uses Build Providers to generate its DAL and code. Please check subsonic configuration for custom build provider. It is open source you can check its implementation also.
<configuration>
<system.web>
<compilation>
<buildProviders>
<add extension=".abp" type="SubSonic.BuildProvider, SubSonic"/>
</buildProviders>
</compilation>
</system.web>
</configuration>
It uses .abp extension file to initiate its build provider.
Edit : Yes, Custom build providers are super feature of ASP.Net. But
traditional winform or other
developers can use MSBuild custom
tasks to get the same effect. Dino
Esposito has provided a great article
for the same. You can check it
here.

I don't know how this would work, but here goes:
If your CodeDOM code is generated in a separate project, generate the classes and then add the file names to the .csproj file (it's just XML) of a library. Have it ordered to build first as well. Then have the library's pre-build event run the code generating app, then it will compile. When you click on VS the next time, it will ask you to reload because the project file has changed and your new classes should show up.
It seems a little hacky, but with a little scripting it could be automated.

Related

How to update appsettings.json based on publish profile using .NET Core?

I'm currently making the switch from .NET Framework to .NET Core. In the past, all of my application settings were in the Web.config file. When I added a new publish profile, I could right click and select 'Add Config Transform' which would generate a nested Web.{Profile}.config file under Web.config where I could set application settings that were specific to the respective profile.
Now, in .NET Core, I want to achieve the same effect using an appsettings.json file instead of Web.config file. How can I create an appsettings.{Profile}.json file which will be nested under my appsettings.json file and contain settings that are specific to my publish profile? Of course, I can create the file manually, but what is it that 'links' the settings so that they will override appsettings.json when the application is published? Is there a simple way to do this in Visual Studio like I described for my old .NET Framework projects? Or am I missing something?
Thanks!
but what is it that 'links' the settings so that they will override
appsettings.json when the application is published?
The appsettings are configured by WebHost in Program.cs
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
In the implementation of webhost.cs the framework adds the appsettings to the webhost:
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
The second line is where it adds the environment specific appsettings. Within Visual Studio this environment variable is defined in the Project Settings -> Debug page and is called ASPNETCORE_ENVIRONMENT. By default it is set to Development so when you build and run within Visual Studio the appsettings.development.json file (if it exists) will be loaded and override any matching settings in the appsettings.json file.
When you publish your application you can override this value using an OS environment variable of the same name. There is an hierarchy of where .NET Core reads the values from and has a "last one wins " policy.
The hierarchy is currently:
Files (appsettings.json, appsettings.{Environment}.json, where {Environment} is the app's current hosting environment)
Azure Key Vault
User secrets (Secret Manager) (in the Development environment only)
Environment variables
Command-line arguments
So when you publish your app you can override the environment on the host OS using an environment variable. When .NET Core starts your published app it will read that variables and load the appropriate appsettings.{environment}.json file. IF the value is not set, or no file exists for that environment, then the settings in appsettings.json will apply.
You can read more about the ASPNETCORE_ENVIROMENT setting here
...and since my original comment, I have since come to find that web.config transforms are fully supported by VS 2017 and MS Build for .NET Core, once you realize the nesting and transform build commands do not need to be part of the project any longer. Do not use the "Add Config Transforms" command on your web.config any longer, unless you find a fix that doesn't corrupt your project file. Simply manually add transform versions of your web.config, and they will automatically nest and run on publish. Yea VS 2017!
The following, in your web.Release.config works very nicely to set your Environment Variable.
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<location>
<system.webServer>
<aspNetCore>
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" xdt:Locator="Match(name)" xdt:Transform="SetAttributes" />
</environmentVariables>
</aspNetCore>
</system.webServer>
</location>
</configuration>
Additionally, with .NET Core 2.2, you no longer need to add the additional appsettings transforms (switching off your Environment Variable,) to your Startup class. This default...
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
...takes care of the accepted answer's code automatically.
The bottom-line is, as an unapologetic Microsoft developer, I still want to assume my application will only be published to an IIS server, using MS Build and Web Deploy, and I would like the ability to configure my application through the application's own config; and I want to be able to do this on Build, not as a publish or post-publish command-line command. If Microsoft or someone creates a simple build plugin for Visual Studio that will transform my appsettings.json file, so I only publish what is necessary for the given environment, I will gladly use it, but I haven't found one, or had the time to write one, yet.
And just so I make sure to answer the OP's question directly: AppSettings can easily be transferred from web.config to appsettings.json, and probably should, as long as you understand ALL of the appsettings.json files are published, and determined at run-time, unlike a true transform solution where only the necessary files and settings are published, based on the requested profile. Using the web.config transform only to set the environment variable necessary to determine which appsettings.{env}.json file to use. Again, this whole discussion goes the way of the Dodo, if we can transform our apsettings.json file the same as our web.config, as the OP requested. I have a feeling it will come someday, if it hasn't already.
Yes, moving from a legacy .NET Framework to .NET Core can be a fun exercise. .NET Core is a huge step forward, but there are a few hurdles to get over; especially for those who have been on legacy since the start.
Here's an ugly work-around:
In an Azure build pipeline, after building the ASP.NET core project, copy the appsettings.Production.json file to a separate folder in the artifact folder.
In the release pipeline, use a 'Replace tokens' task to replace tokens in that json file with release variables.
After deploying the app to IIS copy the 'transformed' appsettings.Production.json to the web site folder.
It works...

How do I modify the template that reference.cs is generated from?

I've been searching on the web for this, and maybe I'm just using the wrong keywords or something? I could use some help.
My problem is simple - we have a bunch of reference.cs files in our solution, which were auto-generated by VS2010 when adding services. These files don't add XML comments by default, so when we build the project, I get 800 or so messages in the build list. This doesn't break anything, but it does make the build take (significantly) longer, and mucks up the output screen.
I "fixed" this by adding the appropriate #pragma statments to the beginning and end of each reference.cs file, but if those ever get regenerated, they will have to be re-added by hand. I'd like to streamline that process and just add them to whatever T4 template VS2010 is using in the first place. The problem is, I don't know where that is, or if VS2010 is using something else to build these files?
Can this be done? Is there a better solution? I don't necessarily want to turn off XML comments for the entire project.
Visual Studio does not use T4 templates to generate the service reference proxy classes (Reference.cs). Instead Visual Studio is most likely using the WsdlImporter and ServiceContractGenerator classes to generate this code.
There is a stackoverflow post on using either a custom wsdl exporter or WCFExtras to add xml comments to the generated code. Both of these assume you have access to the code for the services you are referencing.

app.config Transformations

I'm a huge fan of the addition of web.config transformations in Visual Studio 2010. See also Scott Hanselman's recent talk at MIX2011.
What sucks is that this functionality (appears at least) to only be available to web projects.
In our solution we have several Windows Services that connect to a different database dependant on the environment they are deployed under.
Has anyone come up with a nice, tidy way of achieving similar 'app.config transformation' functionality?
Note: We are using TFS 2010 to build our solutions in a Continuous Integration manner.
I realize you already have an answer, but I stumbled across SlowCheetah this morning which is the best implementation I've seen to date. There is also a blog post on getting this running from a CI server.
You can use the XML transformation functionality with any XML file - we do this all the time. It's available via an MSBuild task.
Try adding the following to your build script:
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>
<TransformXml Source="Path\To\Your\Xml.config"
Transform="Path\To\Your\Xml.$(Configuration).config"
Destination="Path\To\Your\Output.config" />
I wrote nice extension to automate app.config transformation like the one built in Web Application Project
Configuration Transform
Using Luke Bennett's answer to set me off on the right track. I found this to be the answer for us.
FTA (see link for code snippets):
Add a new property ProjectConfigFileName that points to your App.Config file
Add a version of App.Config for each configuration, i.e., App.Debug.config To have them nested under App.Config, edit your csproj file,
Import Microsoft.Web.Publishing.targets into your csproj file right after the Microsoft.CSharp.targets import.
Call the TransformXml task in your AfterBuild target. Note, the BeforeBuild and AfterBuild targets are commented out by default.
If you have multiple client assemblies and don't want to duplicate the same configuration data, I created Profigurator. It'll take a JSON file as input and apply the settings to an app.config or web.config.
It's a little rough as I write this, but I am currently using it on a production system for deploys and it works great.

VS2010 When debugging web.config transforms are not being applied. Building a deployment package works

When I debug a web application, the web.config transforms are not applied.
I simply find that the configuration in web.config is not applying the transform for the configuration I'm currently using.
Yet if I build a deployment package then I find that the web.config does have the current transforms applied.
Are transforms not applied when debugging? I'm starting to wonder if this is the case, but I have coworkers insisting that it works for them.
Web.config transforms are only applied when publishing or deploying.
Jared Harding provided a link where a member of the .NET Team answered this question in the response here: VS2010 Clean Web.configs - not updating
The link he provided for ease of reference is: http://forums.asp.net/p/1532038/3711423.aspx
You can start a transform by introducing a "AfterBuild" entry in your project file as described here.
Downside: you have 2 web.config files...
http://kfigy.blogspot.ch/2010/03/making-visual-studio-2010-webconfig.html

How to deploy SharePoint BDC model package using VS setup project (or at all!)

Background: We have a ClickOnce-deployed WPF app, that talks to WCF Services, which in turn both talk to our own SQL database and also to SharePoint via the Client OM. To set up the WCF and the ClickOnce, we have a Setup project, which takes in details about server paths and database connection strings from the installing user and fires an Installer class to do fun stuff like writing config XML and updating the ClickOnce strapper for that deployment URL and such.
We need to add some BDC Models to SharePoint via this installer, so that end users can use SharePoint list interfaces to configure some of the rarely-changed table values in our database. (As "one-click" an install process as possible is a requirement being imposed by the client.)
Including a BDC Model project in our Visual Studio 2010 solution, we can get a packaged WSP for our BDC stuff, which sounds great...
One problem with this, however, is that in the feature.xml that gets packaged into this WSP, this hard-coded line appears:
<Property Key="SiteUrl"
Value="http://BuildingWorkstationSharePointInstanceUrl/" />
Visual Studio won't build with the feature SiteUrl set to anything other than a SharePoint instance local to the machine (which is pretty lame), so we can't change that pre-WSP.
Furthermore, the .bdcm files themselves have hard-coded connection string information:
<LobSystemInstance Name="DatabaseName">
<Properties>
<Property Name="AuthenticationMode" Type="System.String">PassThrough</Property>
<Property Name="DatabaseAccessProvider" Type="System.String">SqlServer</Property>
<Property Name="RdbConnection Data Source" Type="System.String">DatabaseServer</Property>
<Property Name="RdbConnection Initial Catalog" Type="System.String">DatabaseName</Property>
<Property Name="RdbConnection Integrated Security" Type="System.String">SSPI</Property>
<Property Name="RdbConnection Pooling" Type="System.String">True</Property>
<Property Name="ShowInSearchUI" Type="System.String" />
</Properties>
</LobSystemInstance>
This would also have to be re-written by the installer once the installing user has provided the database connection information.
I'm also not sure what the best approach will be for actually installing the WSP on the server via the MSI (trying to execute a powershell script is all I've thought of so far).
It seems to me like designing BDC models for a third party shouldn't be that obscure of a scenario, but I can't find any information or support on how to overcome any of these problems!
Anyone have any advice?
I ran into this issue as well. I'd like to package our BDC model into a WSP and deploy it via the WSP. Unfortunately (like you've indicated) the BDC model contains specific environment information that must be configured per environment.
What we've landed on is keeping the different BDC models and just importing them instead of packaging them in a WSP. From the sounds of it, you may need to ask for the specific environment information at the time of install and somehow use that.
Two methods you could employ:
If you're using a "Custom" assembly type (instead of a DotNetAssembly as your LobSystem Type),
you can implement IAdministrable to allow you to change properties (either the LobSystem or LobSystemInstance) in the Central Admin. It doesn't seem to work for DotNetAssemblies, even if IAdministrable is implemented.
Alternatively, you can change properties by importing Resource Files. Easiest way to do this is to import your model, then export it as a Resource file and edit the file down to the properties you need changed. Then import the bdcr (resource) file and you'll see an indication that the properties had been changed.
Advanced Installer offers some support for this. Basically, through its XML editor you can use Windows Installer properties instead of hard-coded values in your manifest files.
The other solution I can think of is to use a custom action to modify the files after install.
Either way, this requires a complex installer, like an MSI package. ClickOnce doesn't support it.
If you want to deploy your BDC to a specific siteURL when you deploy it, go to your project folder for your bcd model when you view your solution and in the properties of the folder you should see something called "Feature Properties".
Click on the elipsis to expand the properties and add a heading called "SiteUrl" and set it to be the root of the site you want to deploy it too: i.e "http://spsite".
It will be deployed to that site instead of the Local one.
In our case, we implemented a custom Feature Receiver using instructions located at SharePoint 2010, deploying a BCS Model using a farm property bag to have a dynamic siteurl
It allows to deploy in any environment because the Site Url is discovered during the feature activation.

Resources