I'm creating a site definition with a web-scoped feature that creates a subsite on the current site. I want to activate this feature on the site when an user creates a site based on that definition.
The feature works normally when I activate it, the problem is that I get the following error when I try to create a site based on the definition:
Feature with Id 'Id' is not installed in this farm and cannot be added to this scope.
I tried to change the scope to Farm, but it gets me the error "Error occurred in deployment step 'Add Solution': Unable to cast object of type 'Microsoft.SharePoint.Administration.SPWebService' to type 'Microsoft.SharePoint.SPWeb'", also, I guess it doesn't make sense to have this feature farm-scoped.
My site definition 'web features' node contains:
<WebFeatures>
<Feature ID="6e512cb1-1a3f-43d6-a756-55c1a9eadd2c" />
</WebFeatures>
My Feature Receiver method is:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb web = (SPWeb)properties.Feature.Parent;
if (!web.Webs["subsite1"].Exists)
{
web.Webs.Add("subsite1");
web.Update();
}
}
Please let me know if anyone needs more information.
Open the Feature designer and select Scope: WebApplication
<SiteFeatures>
<Feature ID="C85E5759-F323-4EFB-B548-443D2216EFB5" />
<Feature ID="A392DA98-270B-4e85-9769-04C0FDE267AA" />
<Feature ID="7C637B23-06C4-472d-9A9A-7C175762C5C4" />
</SiteFeatures>
<WebFeatures>
<Feature ID="00BFEA71-DE22-43B2-A848-C05709900100" />
<Feature ID="00BFEA71-E717-4E80-AA17-D0C71B360101" />
</WebFeatures>
<Modules>
<Module Name="Home" />
</Modules>
Related
In the sample that links a Federated login against a pre-created Local Account. If a user does not exist, then an exception is thrown.
This redirects to https://<host>/MicrosoftIdentity/Account/Error
Which, as far as I understand, is this page here
At this stage, I assume there are two possibilities, either:
Customise the error page (somehow); or
Change the Custom Policy so that it doesn't throw an exception and shows a self-asserted page instead (preventing SendClaims)
With regards to option 1, I've tried to find documentation on how I might trap the error or customise this page - but I haven't found anything so far. There is documentation in asp.net core with regards to creating a custom error page - but it doesn't seem to apply in this case:
if (app.Environment.IsDevelopment())
{
//app.UseDeveloperExceptionPage();
app.UseExceptionHandler("/Error");
}
With regards to option 2, I tried changing the AAD-FindB2CUserWithAADOid technical profile so that RaiseErrorIfClaimsPrincipalDoesNotExist is false:
<TechnicalProfile Id="AAD-FindB2CUserWithAADOid">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
<Item Key="UserMessageIfClaimsPrincipalDoesNotExist">An account could not be found for the provided user ID.</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="signInNames.oidToLink" Required="true" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId"/>
<OutputClaim ClaimTypeReferenceId="extension_requiresMigrationBool"/>
<!-- account flagged for linking -->
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
But that resulted in a genuine exception - the api call becomes malformed. I'm not sure why this would be the case.
For this particular circumstance, I'd like to display an Access Denied message. But it would be nice if I could create a stylised page for any Account Error.
Is either strategy okay? Am I missing something?
I've introduced the following to my Program.cs:
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp( options => {
builder.Configuration.GetSection( "AzureB2C" ).Bind( options );
options.Events = new OpenIdConnectEvents
{
OnRemoteFailure = context =>
{
if (context.Failure?.Message.ToUpper().Contains("AADB2C99002") == true)
{
context.Response.Redirect("/account-access");
context.HandleResponse();
return Task.FromResult(0);
}
return Task.CompletedTask;
}
};
});
In the case where the user isn't found (in my case, they haven't been pre-created) then they'll be shown the "Access Denied" page. Which means other errors will come through as they always have.
I'm still not sure if this is an acceptable solution.
I have this problem with wix installer not installing our application IISversion >=10. It works on IISVersion <10.
I found this link on github. https://github.com/wixtoolset/issues/issues/5276
This link suggests adding a custom action which returns ActionResult.Success if IISRegistryversion is >= IISRequiredVersion.
But I am getting the following error. The error happens after this in the log
Doing action: LaunchConditions
Action start 12:46:02: LaunchConditions.
Either the variable is not being set or custom action is not being called.
I have some logging in the custom action but its not logging anything even with verbose on.
How do make sure the launch condition/ custom action is being called before this condition is evaluated? Can anyone suggest please?
This is how Product.wxs looks
<InstallExecuteSequence>
<Custom Action="CA.DS.CreateScriptDirCommand" Before="InstallFinalize">
<![CDATA[NOT Installed AND (&Feature.DatabaseServer.Database = 3)]]>
</Custom>
<Custom Action="Iis.CheckInstalledVersion.SetProperty" Before="LaunchConditions" >
<![CDATA[NOT Installed AND &Feature.WebServer.WebServices = 3]]>
</Custom>
<Custom Action="Iis.CheckInstalledVersion" After="Iis.CheckInstalledVersion.SetProperty" >
<![CDATA[NOT Installed AND &Feature.WebServer.WebServices = 3]]>
</Custom>
</InstallExecuteSequence>
<Condition Message="This application requires IIS [Iis.RequiredVersion] or higher. Please run this installer again on a server with the correct IIS version.">
<![CDATA[Iis.IsRequiredVersion > 0]]>
</Condition>
<Fragment>
<CustomAction Id='Iis.CheckInstalledVersion.SetProperty' Property='Iis.CheckInstalledVersion' Execute='immediate' Value='' />
<!--Note: Changed "Execute" from "deferred" to "immediate", to avoid error "LGHT0204: ICE77: Iis.CheckInstalledVersion is a in-script custom action. It must be sequenced in between the InstallInitialize action and the InstallFinalize action in the InstallExecuteSequence table"-->
<!--Note: Changed "Impersonate" from "no" to "yes", to avoid warning "LGHT1076: ICE68: Even though custom action 'Iis.CheckInstalledVersion' is marked to be elevated (with attribute msidbCustomActionTypeNoImpersonate), it will not be run with elevated privileges because it's not deferred (with attribute msidbCustomActionTypeInScript)"-->
<CustomAction Id='Iis.CheckInstalledVersion' BinaryKey='B.WixCA' DllEntry='CheckInstalledIISVersion' Execute='immediate' Return='check' Impersonate='yes' />
<Component
</Component>
</Fragment>
[CustomAction]
public static ActionResult CheckInstalledIISVersion(Session session)
{
try
{
session.Log("* Starting to check installed IIS version");
const int IisRequiredVersion = 7;
string IISMajorVersionFromRegistry = session["IISMAJORVERSION"];
session.Log(string.Format("*!*! DEBUG; CheckInstalledIisVersion; IIS major version: {0}", IISMajorVersionFromRegistry));
string iisMajorVersionNumeric = IISMajorVersionFromRegistry.Replace("#", string.Empty);
int iisMajorVersion = int.Parse(iisMajorVersionNumeric, CultureInfo.InvariantCulture);
bool isRequiredVersion = iisMajorVersion >= IisRequiredVersion;
// Setting the required version as a custom property, so that it can be used in the condition message
session["IIs.RequiredVersion"] = IisRequiredVersion.ToString(CultureInfo.InvariantCulture);
// Setting the results of the check as "bool"
session["Iis.IsRequiredVersion"] = isRequiredVersion ? "1" : "0";
return ActionResult.Success;
}
catch (Exception ex)
{
session.Log(string.Format("CheckInstalledIisVersion; Error occured SC: {0}", ex.Message));
return ActionResult.Failure;
}
}
It works without the condition. The condition gets executed before
The feature check Feature.WebServer.WebServices = 3 isn't going to work because the feature "to be installed" state isn't set until after costing (and often choosing the feature in the feature dialogs). So the CA isn't being called.
You probably need to rethink this and force the check for IIS after CostFinalize, and then perhaps warn then that IIS is not installed/running etc. So you'd do the search for IIS unconditionally to set the property and not use it as a launch condition. Then give the warning if &Feature.WebServer.WebServices = 3 and the IIS version is too low.
See feature action condition documentation and the reference to CostFinalize:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa368012(v=vs.85).aspx
I want to validate a custom content type document(xml kind), with an custom validator. Want to validate it with a xsd, but only after certain preprocessing of main document.
Normal xml validator can't be used because-
1.) The schema location(xsd) & namespaces are not defined in the main document file.
2.) And bcz of first reason & many more, want to do some preprocessing to the document file, before applying xsd validation.
So I want to use the xml validator, but only after preprocessing of my file.
My plugin.xml is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension
point="org.eclipse.core.runtime.contentTypes">
<content-type
id="com.xyz.ide.core.contentType.dummy"
base-type="org.eclipse.core.runtime.xml"
file-extensions="blabla"
/>
</extension>
<extension
point="org.eclipse.wst.sse.ui.sourcevalidation">
<validator
scope="total"
class="mc.CustomValidator"
id="com.xyz.myValidator">
<contentTypeIdentifier
id="com.xyz.ide.core.contentType.dummy">
<partitionType
id="org.eclipse.wst.xml.XML_DEFAULT">
</partitionType>
</contentTypeIdentifier>
</validator>
</extension>
</plugin>
CustomValidator.java
public class CustomValidator implements ISourceValidator, IValidator {
XMLValidator validator = new XMLValidator();
IDocument document;
public void validate(IValidationContext helper, IReporter reporter) {
String fileContent = this.document.get();
final InputStream is = new ByteArrayInputStream(fileContent.toLowerCase().getBytes());
// Whats the problem in this line???
XMLValidationReport report = validator.validate("/home/rchawla/xmlWorkspace/abc.xsd", is);
ValidationMessage[] messages = report.getValidationMessages();
for(ValidationMessage message:messages){
System.out.println(message.getMessage());
}
}
I can hit the validate method on running the plugin in debug mode, but
the document is not getting validated with the xsd.
What is wrong in the above method as,
ValidationMessage[] messages = report.getValidationMessages(); is giving zero messages, even though the there are errors in the main document file.
I also had a lot of trouble trying to make org.eclipse.wst.sse.ui.sourcevalidation extension point work. I ended up using another extension point org.eclipse.wst.validation.validatorV2. The only difference between the 2 validators is that this one is only triggered when you save a file, not while you are typing. See an example bellow :
<extension id="customValidator" name="Custom Validator" point="org.eclipse.wst.validation.validatorV2">
<validator class="aaa.bbb.CustomValidator" markerId="customMarker" version="3">
<include>
<rules>
<contentType id="customContentType" exactMatch="false"/>
</rules>
</include>
</validator>
</extension>
Your implementation of the validator should override org.eclipse.wst.validation.AbstractValidator.
With Windows Installer 4.5, there was a new table added for MsiEmbeddedChainer Table. This table was supposed to allow multiple-package installation. WiX added support for the table by creating the EmbeddedChainer element. I've read the wiki, but are there any examples on how to use the element?
I'm attempting to install a JRE before my program.
Embedded chainers only work after the installer that contained them is installed, and can only install raw .msi files (.msi files with their own bootstrap .exe files cannot be used), so I don't think you'll be able to install the JRE the way you want.
Do the following steps:
Changes in WXS file:
...
<Component DiskId="1" Guid="5CE59096-E197-4694-8DC2-E8EB4601C7C5" Id="CHAINERRUN.EXE">
<File Id="CHAINERRUN.EXE" Name="ChainerRun.exe" Source="..\ClinAppChainers\bin\ChainerRun.exe" />
<File Id="MICROSOFT.DEPLOYMENT.WINDOWSINSTALLER.DLL" Name="Microsoft.Deployment.WindowsInstaller.dll" Source="C:\Program Files\Windows Installer XML v3.6\SDK\Microsoft.Deployment.WindowsInstaller.dll" />
<File Id="MICROSOFT.CSHARP.DLL" Name="Microsoft.CSharp.dll" Source="C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Microsoft.CSharp.dll" />
<File Id="SYSTEM.DLL" Name="System.dll" Source="C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll" />
<File Id="SYSTEM.CORE.DLL" Name="System.Core.dll" Source="C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll" />
<File Id="SYSTEM.XML.DLL" Name="System.Xml.dll" Source="C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Xml.dll" />
<File Id="SYSTEM.XML.LINQ.DLL" Name="System.Xml.Linq.dll" Source="C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Xml.Linq.dll" />
</Component>
...
<EmbeddedChainer Id="ChainerRun" FileSource="CHAINERRUN.EXE" />
The FileSource is the reference to the File element ID defined in the component
Create a C# project, reference to the file Microsoft.Deployment.WindowsInstaller.dll, or create a new WIX "C# Custom action project" then change the output to Console application EXE instead of DLL. The body of the CS file should contain the Main function
ChainerRun.CS
namespace ChainerRun
{
public class CustomActions
{
static void Main(string[] args)
{
System.Diagnostics.Debugger.Launch();
try
{
IntPtr ptr = new IntPtr(Convert.ToInt32(args[0], 16));
//ptr = System.Runtime.InteropServices.Marshal.StringToCoTaskMemAuto(args[0]);
Transaction transaction = Transaction.FromHandle(ptr, true);
transaction.Join(TransactionAttributes.JoinExistingEmbeddedUI);
// Installer.InstallProduct(#"c:\MyOtherApp.msi", argline);
transaction.Commit();
transaction.Close();
}
catch (Exception e)
{
throw e;
}
}
[CustomAction]
public static ActionResult CustomAction1(Session session)
{
System.Diagnostics.Debugger.Launch();
session.Log("My CustomAction1() begins ...");
}
}
There is a bug in the c# code below: In the line "IntPtr ptr = new IntPtr(Convert.ToInt32(args[0], 16));" the "16" must be a "10"!
Otherwise you will get "bad handle" errors when there are more than 10 transactions (e.g. when there are five or more sub msi's called from the embedded chainer).
The approach to embed the JRE as a package in a multi package transaction is an overkill which unnecessarily complicates maintenance.
There are two reasonable solutions with low maintenance.
Use burn and install the JRE as a separate package in the bundle. Advantage of being able to use a prepared installation such as the ones from Oracle.
The JRE by design is self versioned and requires no registrations or special handling, given that it may be best to include the jre in the main application MSI. This is a practice that I've seen in many professional java-based applications and has the added advantage of easily creating application shortcuts by referencing java.exe directly.
We have a few MSI packages (generated by WIX) that install WCF services. Most of these services need net.tcp for their endpoint bindings.
I'd like to make our deployment life easier and automate the process of adding net.tcp.
I already know the WixIisExtension.dll and make use of its useful functions (create web site, virt. directory, etc.).
Can I use the WixIisExtension to enable the net.tcp protocol?
If not, how can I achieve that?
Add a new Project to your Setup Solution (Windows Installer XML -> C# Custom Action Project)
In this Project add a reference to the Assembly Microsoft.Web.Administration, which can be found here: C:\Windows\System32\inetsrv and is required to add the protocols.
My Custom Action looks like this:
using System;
using System.Linq;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Web.Administration;
namespace Setup.CustomAction.EnableProtocols
{
public class CustomActions
{
[CustomAction]
public static ActionResult EnableProtocols(Session session)
{
session.Log("Begin EnableProtocols");
var siteName = session["SITE"];
if (string.IsNullOrEmpty(siteName))
{
session.Log("Property [SITE] missing");
return ActionResult.NotExecuted;
}
var alias = session["VIRTUALDIRECTORYALIAS"];
if (string.IsNullOrEmpty(alias))
{
session.Log("Property [VIRTUALDIRECTORYALIAS] missing");
return ActionResult.NotExecuted;
}
var protocols = session["PROTOCOLS"];
if (string.IsNullOrEmpty(protocols))
{
session.Log("Property [PROTOCOLS] missing");
return ActionResult.NotExecuted;
}
try
{
var manager = new ServerManager();
var site = manager.Sites.FirstOrDefault(x => x.Name.ToUpper() == siteName.ToUpper());
if (site == null)
{
session.Log("Site with name {0} not found", siteName);
return ActionResult.NotExecuted;
}
var application = site.Applications.FirstOrDefault(x => x.Path.ToUpper().Contains(alias.ToUpper()));
if (application == null)
{
session.Log("Application with path containing {0} not found", alias);
return ActionResult.NotExecuted;
}
application.EnabledProtocols = protocols;
manager.CommitChanges();
return ActionResult.Success;
}
catch (Exception exception)
{
session.Log("Error setting enabled protocols: {0}", exception.ToString());
return ActionResult.Failure;
}
}
}
}
Please note that I am assuming three properties here: SITE, VIRTUALDIRECTORYALIAS & PROTOCOLS
Build the solution now. In the background, WiX creates two assemblies %Project%.dll and %Project%.CA.dll. The CA.dll includes the depending Microsoft.Web.Administration automatically.
Then in your WiX Setup Project include a reference to the new Custom Action Project. The reference is required for referencing the %Projet%.CA.dll.
Edit the product.wxs
First add the properties somewhere inside the product element:
<!-- Properties -->
<Property Id="SITE" Value="MySite" />
<Property Id="VIRTUALDIRECTORYALIAS" Value="MyVirtDirectoryAlias" />
<Property Id="PROTOCOLS" Value="http,net.tcp" />
Below add the binary element:
<!-- Binaries -->
<Binary Id="CustomAction.EnableProtocols" SourceFile="$(var.Setup.CustomAction.EnableProtocols.TargetDir)Setup.CustomAction.EnableProtocols.CA.dll" />
Note that you have to add the CA.dll.
Below add the Custom Action:
<!-- Custom Actions -->
<CustomAction Id="EnableProtocols" BinaryKey="CustomAction.EnableProtocols" DllEntry="EnableProtocols" Execute="immediate" Return="check" />
And finally the Installation Sequence where you want the execution to take place.
<!-- Installation Sequence -->
<InstallExecuteSequence>
<Custom Action="EnableProtocols" After="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
that's all. Should work.
Thanks to Darin Dimitrov for providing the links above.
Here is the right way to do this in WIX (assuming you are installing on a 64-bit operating system - if not at a guess I'd say change CAQuietExec64 to CAQuietExec although this is untested):
Get a reference to appcmd.exe:
<Property Id="APPCMD">
<DirectorySearch Id="FindAppCmd" Depth="1" Path="[WindowsFolder]\system32\inetsrv\">
<FileSearch Name="appcmd.exe"/>
</DirectorySearch>
</Property>
Define the following custom actions (the properties [WEB_SITE_NAME] and [WEB_APP_NAME] can be populated elsewhere in your installer; or to test you can hard-code them):
<CustomAction
Id="SetEnableNetTCPCommmand"
Property="EnableNetTCP"
Value=""[APPCMD]" set app "[WEB_SITE_NAME]/[WEB_APP_NAME]" /enabledProtocols:http,net.tcp"/>
<CustomAction
Id="EnableNetTCP"
BinaryKey="WixCA"
DllEntry="CAQuietExec64"
Execute="deferred"
Return="ignore"
Impersonate="no" />
Now in the InstallExecuteSequence add
<InstallExecuteSequence>
...
<Custom Action="SetEnableNetTCPCommmand" After="InstallExecute">APPCMD AND NOT Installed</Custom>
<Custom Action="EnableNetTCP" After="SetEnableNetTCPCommmand">APPCMD AND NOT Installed</Custom>
...
</InstallExecuteSequence>
And if all is well in the world that will now update the protocols.
You may take a look at this article on MSDN. There's a section at the end which illustrates how to use the managed API to achieve configure a WAS enabled service. I am not familiar with Wix but you could probably use and plug this code into some custom deployment step.
This can't be done using the standard WiXIIsExtension, as far as I know. Thus, the only option you have is a custom action.
You can also find this thread interesting - it gives a hint how to achieve the similar thing in MSBuild script, but you should be able to translate it to custom action easily.
Good luck!