How to get the value of an MSBuild variable - msbuild

How can I get the value of MSBuild variable (ex. $(MSBuildToolsPath), $(MSBuildAssemblyVersion), $(TargetFrameworkIdentifier), etc.).
I need to get the value on the C# side, but I can access msbuild.exe if it's not available from the C# code.

BuildManager and the likes are for building, only; Microsoft decided to split up the MSBuild API in different namespaces according to functionality. Once you know that it's not too hard figuring out what you need: you just need to evaluate properties, so the Project class from the Evaluation namespace seems like the proper choice. It has a Properties member exposing all properties:
var project = new Microsoft.Build.Evaluation.Project( #"my.vcxproj" );
foreach( var property in p.Properties )
{
System.Console.WriteLine( "{0} = {1}",
property.Name, property.EvaluatedValue );
}

Related

Updating and inserting in an OData service

I have a Xamarin.Forms Visual Studio solution, into which I installed the “Simple.OData.Client” package with NuGet. I have the URI of an OData service and I want to load items from the table “Persons”, in which the base element type is “Person” and which contains instances of the class “Customer”, which inherits from the class “Person”, as I can see when opening the URI to which I append “/$metadata”.
<Schema xmlns="http://schemas.microsoft.com/ado/2009/11/edm" Namespace="A">
...
<EntityType Name="Person" Abstract="true">
...
<EntityType Name="Customer" BaseType="A.Person">
...
<EntityContainer Name="Model" m:IsDefaultEntityContainer="true">
...
<EntitySet Name="Persons" EntityType="A.Person"/>
...
I create an instance of the service:
ODataClient clientSimple = new ODataClient("http://.../.../odata.v3/default");
I load items from the data table:
System.Collections.Generic.IEnumerable<System.Collections.Generic.IDictionary<string, object>> persons = await clientSimple.For("Persons").FindEntriesAsync();
The items are returned as dictionaries where the keys are the property names and the values are the property values. I see that the properties from the “Person” entity type as well as those added in the derived “Customer” type are present.
I know that there is also a possibility of the typed syntax:
var personsTyped = await clientSimple.For<Person>().FindEntriesAsync();
However, I do not know where to get the definition of the “Person” class so that I can use it here as the generic type parameter.
Then I want to modify an entry in the OData service:
await clientSimple.For("Persons").Key(1).Set(new { FirstName = "Johnny" }).UpdateEntryAsync();
This works as long as I only update a property defined in the “Person” entity type, but trying to modify a property added in the “Customer” entity type raises an exception:
await clientSimple.For("Persons").Key(1).Set(new { FirstName = "Johnny", SalesPerson = "..." }).UpdateEntryAsync();
[Simple.OData.Client.UnresolvableObjectException] No property or association found for [SalesPerson].
Trying to insert a new item also fails:
var newObjectCreated = await clientSimple.For("Persons").Set(new { FirstName = "...", ... }).InsertEntryAsync();
[Simple.OData.Client.WebRequestException] Internal Server Error
How can I solve this so that I can update all properties and insert new items?
There are several source of information that might be useful for you. First, I suggest you have a look at Simple.OData.Client wiki pages, in particulary pages that give examples of how to modify data:
https://github.com/object/Simple.OData.Client/wiki/Modifying-data
Then there are plenty of examples that you can get from the project tests, look here for example:
https://github.com/object/Simple.OData.Client/blob/master/Simple.OData.Client.Tests.Net40/InsertTests.cs
https://github.com/object/Simple.OData.Client/blob/master/Simple.OData.Client.Tests.Net40/InsertTypedTests.cs
https://github.com/object/Simple.OData.Client/blob/master/Simple.OData.Client.Tests.Net40/UpdateTests.cs
https://github.com/object/Simple.OData.Client/blob/master/Simple.OData.Client.Tests.Net40/UpdateTypedTests.cs
And if you want to use typed syntax (which I recommend) you should define your entity types yourself, currently Simple.OData.Client doesn't have any entity type generation utility.

Error querying DTO navigation properties with "any"

In my BreezeController I have a method that returns a DTO with two properties. One property is a navigation property to one of my entities, and the other a boolean:
Public Function ProjectList() As IQueryable
Return From p In _contextProvider.Context.Projects
Where Not p.IsDeleted
Select New ProjectListItem() With {
.Project = p,
.HasTasks = (From t In _contextProvider.Context.ProjectTasks Where t.ProjectID = p.ID).Any()
}
End Function
Public Class ProjectListItem
Public Property Project As Project
Public Property HasTasks As Boolean
End Class
Simple queries against this method work fine, but my Project class has a collection of project managers, and using an "any" query against this collection is failing in the Breeze client code, before sending the query to the server, with the following error message:
Exception was thrown at line 10698, column 13 in http://localhost:2780/myapp/Scripts/breeze.debug.js
0x800a138f - JavaScript runtime error: Unable to get property 'isAnonymous' of undefined or null reference
This is in the proto._validate method of FnNode, where entityType is null.
My query (I'm trying to find all projects for a specific project manager) is built up in pieces, but the relevant parts are:
var p = breeze.Predicate.create("ProjectManagerID", op.Equals, id);
var predicate = breeze.Predicate.create("Project.ProjectManagers", "any", p);
// code common to all queries...
var query = breeze.EntityQuery.from("ProjectList");
query = query.where(predicate);
query = query.select("Project.Prop1,Project.Prop2,Project.etc,HasTasks");
return query.using(this.manager).execute();
I create other predicates and run them through the same common logic and they work fine, so it seems to be limited to "any" queries, e.g. this one works...
predicate = breeze.Predicate.create("Project.ClientNumber", op.Contains, search)
.or("Project.ClientName", op.Contains, search)
.or("Project.Notes", op.Contains, search);
I am still using Breeze 1.4.16 (WebAPI v1, .NET 4.0), but have tried updating the Breeze.Client package to 1.5.1, which makes no difference.
Any ideas what I'm doing wrong?
If I manually build the OData query I am looking for, then I get the results that I want, e.g.
http://localhost:1234/myApp/breeze/myController/ProjectList?$filter=Project/ProjectManagers/any(p:p/ProjectManagerID eq 234)&$select=Project/Prop1,Project/Prop2,HasTasks

Tridion 2011 - Engine.GetObject overloads

I found the following difference between the old VBScript API and the .Net API:
In the old VBScript API it's possible to invoke "TDSE.getObject" to retrieve a Tridion object passing by the webdav path, an integer to select how to open it (read only, read and write, etc) and the ID of the publication where there is the exact element of the blueprint we want.
In the new .Net API all I found was "Engine.GetObject" but it only receives the TCM ID or the webdav path of an element.
Our scenario is the following; in the old VBScript code, this overload of the getObject method was used to avoid some permission issues detected while using TCM IDs instead of the webdav paths and because it's much more handful when you need to copy the code between different environments (see DEV, PREPROD and PROD for example), avoiding changing TCM IDs.
So my questions are:
Is there and overload like the old one in the new .Net API?
If not, is there a way of retrieving items by webdav keeping in mind that some of them could be localized and changed from their parent? (the old way works with this, if you send the root webdav path it will retrieve local objects even if their names aren't exactly the same as the parents)
Thank you!
Do you want to be able to use the webdav url of the top-level item, and specify the publication id from which to get the item?
I would create an extension method on Engine that does this for you:
public static T GetObject<T>(this Engine engine, string webDavUrl, int publicationId)
where T : IdentifiableObject
{
[logic to retreive the item and then if needed
get the correct tcm uri and get the intended item]
return item as T;
}
However, this is quite an expensive operation since you get two objects instead of one. So I dont know if I would use this method very often.
Here some samples
IdentifiableObject item = engine.GetObject(new TcmUri("tcm:5-677"));
//will give you the latest approved version in the publication 5.
IdentifiableObject item = engine.GetObject(new TcmUri("tcm:5-677-v0"));
//will give you the WF or Editable version.
TcmUri uri = new TcmUri("tcm:5-677");
uri.PublicationId = 6;
IdentifiableObject item = engine.GetObject(uri);
//will give you the latest approved version in the publication 6.
Engine.GetObject has 4 overloaded method.
GetObject(Session, string)
GetObject(string)
GetObject(TcmUri)
GetObject(Item)
You can check the Tom.Net Api for more details.
Actually, using Engine.GetObject Method (String) should work.
public virtual IdentifiableObject GetObject(
string itemUriOrWebDavUrl
)
You can do something in this way:-
Get the Object based on WebDav URL
Get the TCM ID from this object
Based on your publication, modified your TCM ID accordingly and do your stuff
OR
Try something this way too:-
Repository testRepository = (Repository)session.GetObject("tcm:0-2-1");
Component testComponent = (Component)testRepository.GetObject(webdavURL); //Assuming actual TCM ID is "tcm:1-3"
Console.WriteLine(testComponent.Id); // should show "tcm:2-3"
// Do Your Other Stuff

Microsoft.Deployment.WindowsInstaller.ProductInstallation does not have UpgradeCode property

I am trying to make use of the WiX library to do some machine product analysis for a project I am on. I am scratching my head as to why this is absent from the class in the title?
Is there a way to get this from the WiX library that I am missing? I know how to do it with msi.dll interop, but wanted to try to do everything from the one library. It just seems odd to me that such a key part of an MSI package is missing.
WiX version is 3.5.2519.0
The ProductInstallation class encapsulates the MsiGetProductInfo function found in Msi.dll. Since this function doesn't expose UpgradeCode neither does ProductInstallation.
ProductInstallation does have the InstallSource member (INSTALLPROPERTY_INSTALLSOURCE equiv ) and you can use that to construct an InstallPackage class and access it's Property accessor.
static public string GetPackageUpgradeCode(string packagePath)
{
string upgradeCode = string.Empty;
using (InstallPackage package = new InstallPackage(packagePath, DatabaseOpenMode.ReadOnly))
{
upgradeCode = package.Property["UpgradeCode"];
}
return upgradeCode;
}
If you really don't want to add another refrence you can open it as a Database and use the ExecuteScalar member to select the UpgradeCode value from the Property table.

NHibernate: How to get mapped values?

Suppose I have a class Customer that is mapped to the database and everything is a-ok.
Now suppose that I want to retrieve - in my application - the column name that NH knows Customer.FirstName maps to.
How would I do this?
You can access the database field name through NHibernate.Cfg.Configuration:
// cfg is NHibernate.Cfg.Configuration
// You will have to provide the complete namespace for Customer
var persistentClass = cfg.GetClassMapping(typeof(Customer));
var property = persistentClass.GetProperty("FirstName");
var columnIterator = property.ColumnIterator;
The ColumnIterator property returns IEnumerable<NHibernate.Mapping.ISelectable>. In almost all cases properties are mapped to a single column so the column name can be found using property.ColumnInterator.ElementAt(0).Text.
I'm not aware that that's doable.
I believe your best bet would be to use .xml files to do the mapping, package them together with the application and read the contents at runtime. I am not aware of an API which allows you to query hibernate annotations (pardon the Java lingo) at runtime, and that's what you would need.
Update:
Judging by Jamie's solution, NHibernate and Hibernate have different APIs, because the Hibernate org.hibernate.Hibernate class provides no way to access a "configuration" property.