msiexec: Silent deploy website to IIS - iis

Our team at work has written a wrapper application/interface to install a series of msi's silently using msiexec.
My issue relates to installing the msi's directed at IIS.
I keep getting the following error
Error 1314. The specified path 'Default Web Site/ROOT/someVirtual' is
unavailable. The Internet Information Server might not be running or
the path exists and is redirected to another machine. Please check the
status of this virtual directory in the Internet Services Manager.
The msi gets executed with the following parameters set as follows
msiexec.exe /i "D:\SOME.msi" UseShellExecute="false" TARGETSITE="Default Web Site" TARGETVDIR="someVirtual" TARGETAPPPOOL="DefaultAppPool" /qn /l* D:\SOME_log.txt
I realize this issue is stricly IIS related as I'm probably missing some setting/option that i need to setup.
As far as I can see my virtual is in this location "NT4334RB\Sites\Default Web Site\someVirtual", so my best guess would be that "Default Web Site/ROOT/someVirtual" - ROOT is the issue and needs to be set, but to what? and how?
I just came across this line in the logfile - I think this might be of use?
Getting AppRoot From Url key 'TARGETURL'

Seemed like my issue was related to me not specifying the metabase path correctly.
I ended up adding a helper in my code to the likes of this.
Found various solutions on SO (this got me thinking in the right direction), & I also installed something called IIS Metabase Explorer which was quite useful
//Added for reference purposes
//HasRequiredOption("site|s=", "The site location", c =>
//AddOrUpdateAdditionalMsiProperty("TARGETSITE", BuildMetabasePath(c)));
//apppool => TARGETAPPPOOL
//virtualdir => TARGETVDIR
/// <summary>
/// Builds the meta-base path.
/// </summary>
/// <param name="websiteName">Name of the website.</param>
/// <returns>The fully constructed meta-base path</returns>
private string BuildMetabasePath(string websiteName)
{
return "/LM/W3SVC/" + this.GetWebSiteId(websiteName);
}
/// <summary>
/// Gets the web site id.
/// </summary>
/// <param name="websiteName">Name of the website.</param>
/// <param name="serverName">Name of the server. Defaults to: localhost if none specified</param>
/// <returns>The website id</returns>
private string GetWebSiteId(string websiteName, string serverName = "localhost")
{
using (var entries = new DirectoryEntry(string.Format("IIS://{0}/w3svc", serverName)))
{
var children = entries.Children.Cast<DirectoryEntry>();
var sites =
(from de in children
where
de.SchemaClassName == "IIsWebServer" &&
de.Properties["ServerComment"].Value.ToString() == websiteName
select de).ToList();
if (sites.Any())
{
return sites.First().Name;
}
}
return "-1";
}

Related

Show Azure blob image file in browser and dont force download

This question has been asked before a while ago. I'm hoping the answer is different today.
3 years ago - Azure storage files force download to browser
I am using Azure blob storage to save images (jpg) for a web site. I am linking directly to the files in my <img> tags and that is working great (have enabled anonymous access). The problem is that if the user clicks on the image (which links directly to the file) they are forced to download it and can not view it in the browser.
Is there a way to set the headers for the blob storage to allow viewing it directly in the browser and not forcing a download.
Update 1:
Based on this How can I view an image from Azure Blob Storage, rather than download it? and this https://social.msdn.microsoft.com/Forums/windowsapps/en-US/b8759195-f490-420b-a587-2bb614366ad2/embedding-images-from-blob-storage-in-ssrs-report-does-not-work
I found that I am not setting the content type, which is causing the problem. I need to set it to "image/jpeg". Im not quite sure how to do that however. This is the code I am using to store the image.
using Microsoft.Azure.Storage.Blob
/// <summary>
/// Save a file to azure blob storage.
/// </summary>
/// <param name="name">Name of file</param>
/// <param name="file">filestream</param>
/// <param name="ct">Cancellationtoken</param>
public async Task<bool> SaveFile(Stream fileStream, string fileName, CancellationToken ct)
{
CloudBlockBlob cloudBlockBlob = _blobContainer.GetBlockBlobReference(fileName);
fileStream.Position = 0;
await cloudBlockBlob.UploadFromStreamAsync(fileStream, ct);
return true;
}
I have not found any type of ".Content", or "Type" property on this. Will keep digging.
Update 2: may have found the solution:
cloudBlockBlob.Properties.ContentType = "image/jpg";
Testing
Update 3: That did it. Using this to set proper content types for images and pdf and they are now viewable in the browser.
if (fileName.EndsWith(".jpg"))
{
cloudBlockBlob.Properties.ContentType = "image/jpg";
}
else if (fileName.EndsWith(".pdf"))
{
cloudBlockBlob.Properties.ContentType = "application/pdf";
}
See question for details. But setting content type can be done with:
cloudBlockBlob.Properties.ContentType = "image/jpg";

Why am I getting "A route named 'swagger_docs' is already in the route collection" after I publish my API App?

After publishing my API App I'm getting the yellow error screen of ASP.NET. The error message says "A route named 'swagger_docs' is already in the route collection".
How can I fix this?
This is not related to API Apps per se but more around Web API. What triggers the error is pretty simple:
You publish the API App which is based on Web API.
You discard your project and start working on a new API App based on Web API
You want to publish the new API App instead of the old API App you created at step 1.
You select the API App during "Publish.." and you get the publishing profile of the existing API App we deployed at step 1.
You deploy using Web Deploy and the publishing profile, the new API App on top of the old one.
That will trigger the issue I've explained before. That happens because there are two routes being registered by Swashbuckle when you try to start the app. One of the old one and one of the new one. That's because the old files are still present at the destination.
To solve this, during Web Deploy, click on the Settings tab and then expand the "File Publish Options". There is a checkbox there, called "Remove additional files from destination". This will fix the issue as it will only leave the files you deploy at the destination and not the old ones as well.
Hope it helps.
What if it happens when trying to debug the app locally ?
This happened for me, and the reason was, I renamed my assembly name. So the bin folder had two dlls for the same project with different names which caused this error. Once I deleted the old named dll all is well. Hope this helps.
This happens because You probally are configuring you route in your WebApiConfig class and SwaggerConfig class, as explained below:
WebApiConfig file:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
SwaggerConfig.Register();
}
}
SwaggerConfig file:
using Swashbuckle.Application;
[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]
namespace NEOH.Api
{
public class SwaggerConfig
{
public static void Register()
{
What you should do is remove the assembly call on SwaggerConfig file.
It should work.
My Solution & Cause:
I had the same problem when I renamed NamesSpaces,Refactored,etc.
After reading what everyone else did here's what I tried:
Cleaned the Solution in Visual Studio
Cleaned the Bin folder manually
Checked the nameSpace in the Project Properties (copied it just in case) >> Build tab >> Scrolldown to Output and ensure the XML documentation file is correct. You will need this name later.
Opened up: SwaggerConfig.cs >> fixed the name space in here (copy,paste) c.SingleApiVersion("vX","NameSpace")
Scrolled down until I found: GetXmlCommentsPath() copied and pasted the correct name space in the .xml file path.
Ran, smoke tested, finished this post.
My issue was that I was referencing another project that had the Swashbuckle extension.
Here is how I kept both projects without changing the anything in project that was referenced:
Remove the routes created by the project referenced under SwaggerConfig.cs > Register right before GlobalConfiguration.Configuration.EnableSwagger(...).EnableSwaggerUi(...);:
// Clears the previous routes as this solution references another Swagger ASP.NET project which adds the swagger routes.
// Trying to add the Swagger routes more than once will prevent the application from starting
GlobalConfiguration.Configuration.Routes.Clear();
Then, the application will be able to start, but you will see the operations/functions that are in both projects. To remove the operations from the project being referenced...
Create the following class
using Swashbuckle.Swagger;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http.Description;
namespace yournamespace.Models
{
/// <summary>
/// This class allows to manage the Swagger document filters.
/// </summary>
public class SwaggerCustomOperationsFilter : IDocumentFilter
{
/// <summary>
/// Applies the Swagger operation filter to exclude the Swagger operations/functions
/// that are inherited by the other Swagger projects referenced.
/// </summary>
///
/// <param name="p_swaggerDoc">Swagger document</param>
/// <param name="p_schemaRegistry">Swagger schema registry</param>
/// <param name="p_apiExplorer">Api description collection</param>
public void Apply(SwaggerDocument p_swaggerDoc, SchemaRegistry p_schemaRegistry, IApiExplorer p_apiExplorer)
{
IEnumerable<ApiDescription> externalApiDescriptions = p_apiExplorer.ApiDescriptions
.Where(d => d.ActionDescriptor.ControllerDescriptor.ControllerType.Module.Name != GetType().Module.Name);
IEnumerable<int> externalApiDescriptionIndexes = externalApiDescriptions
.Select(d => p_apiExplorer.ApiDescriptions.IndexOf(d))
.OrderByDescending(i => i);
IEnumerable<string> externalPaths = externalApiDescriptions.Select(d => $"/{d.RelativePathSansQueryString()}");
foreach (string path in externalPaths)
{
p_swaggerDoc.paths.Remove(path);
}
foreach (int apiDescriptionIndex in externalApiDescriptionIndexes)
{
p_apiExplorer.ApiDescriptions.RemoveAt(apiDescriptionIndex);
}
}
}
}
And add the following in SwaggerConfig.cs > Register > GlobalConfiguration.Configuration.EnableSwagger(...)
c.DocumentFilter<SwaggerCustomOperationsFilter>();
Alternative cause of this problem:
Seems like a lot of people have this issue resolved by deleting their "bin" and "obj" folders as per the other answers.
However the cause of the issue might be that you are configuring your Swagger Config in a referenced project, as per this comment: https://github.com/domaindrivendev/Swashbuckle/issues/364#issuecomment-226013593
I received this error when one project with Swagger referenced another
project with Swagger. Removing the reference fixed the problem.
This caused me to split some core functionality out into a Third project that both of my API's could reference, rather than them referencing each other.

Receiver ListUrl is not working in Event Receivers for particular list?

I trying to debug EventReceiver is not working. It use to work properly. Only thing I changed is added Intraner AAM.
http:// spfoundation/dept/it/Lists/App%20Change%20Request/AllItems.aspx
Above url is the default AAM and list url.
<Receivers ListUrl="Lists/App%20Change%20Request">
<Receiver>
<Name>AppChangeEventReceiverItemAdded</Name>
<Type>ItemAdded</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>AppChangeRequest.AppChangeEventReceiver.AppChangeEventReceiver</Class>
<SequenceNumber>10000</SequenceNumber>
</Receiver>
public class AppChangeEventReceiver : SPItemEventReceiver
{
/// <summary>
/// An item was added.
/// </summary>
public override void ItemAdded(SPItemEventProperties properties)
{
// base.ItemAdded(properties);
using (SPWeb web = properties.OpenWeb())
{
try
{
web.AllowUnsafeUpdates = true;
SPList list = web.Lists["Project/Task Status Details"];
......
......
web.AllowUnsafeUpdates = false;
}
catch (Exception ex)
{
throw ex;
}
}
}
In visual studio 2012, I was able to debug properly. Now I am not. Anything wrong I did here? Breakpoint not reaching even first line of it. "No symbols have been loaded..."
There are a few things you can try
1- Delete the dll of your project in GAC (C:\Windows\Microsoft.NET\assembly\GAC_MSIL)
2- Deploy project again
3- Control the dll if its the last deployed one.(control the date)
4- From the vs2012
-debug and attach to process (w3wp.exe and OWSTIMER.exe)
if this does not work, restart vs2012 and try steps again.
I hope it will help you!!
It may be a late answer but still. I killed half of a day figuring out very similar issue in my environment. It is really possible that if AAM is set up incorrectly, event receivers won't be fired (although the site is loaded and everithing works well... well, almost everything). In that case you'll probably find an error like this in the event log:
Event receiver threw an exception: System.IO.FileNotFoundException: The Web application at http://xxx.yyy.zzz/sites/aaa could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.

sharepoint event receiver never fire

I tried to follow a few examples on how to create sharepoint event receiver. Most examples are fairly straightforward in instructions. So I was able to create a sharepoint event receiver project (for example: item adding or site deleting) in visual studio 2010 and deployed to server and site. I checked the feature and it is activated. I ran some test like deleting a test site or even uploading a file. But the test error messages i put in the code never run. I cannot figure out why the events are never fired.
The following is an example of my code:
using System;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
namespace DeletingSite.EventReceiver1
{
/// <summary>
/// Web Events
/// </summary>
public class EventReceiver1 : SPWebEventReceiver
{
/// <summary>
/// A site is being deleted.
/// </summary>
public override void WebDeleting(SPWebEventProperties properties)
{
base.WebDeleting(properties);
properties.Cancel = true;
properties.ErrorMessage = "You cannot ";
}
}
}
Under Event Receiver item, there would be element.xml file. This file defines how and where your event receiver is attached. Please check if everything is correct within that file.

Strange behavior of Windows Azure Compute Emulator (SDK 1.8) with multiple role instances on a clean machine with VS2012 but WITHOUT VS2010

Have you ever tried to run a hosted service in the windows azure emulator with full IIS and multiple role instances? Some days ago I noticed that only one of the multiple instances of a web role is startet in IIS at a time. The following screenshot illustrates the behavior and the message box in front of the screenshot shows the reason for this behavior. The message box appears on trying to start one of the stopped websites in the IIS Manager.
Screenshot: IIS with stopped Websites
The sample cloud application contains two web roles: MvcWebRole1 and WCFServiceWebRole1 each configured to use three instances. My first thought was: "Sure! No port collision will happen in the real azure world because every role instance is an own virtual machine. It cannot work in the emulator!" But after some research and analyzing many parts of the azure compute emulator I found out that the compute emulator creates a unique IP for each role instance (in my example from 127.255.0.0 up to 127.255.0.5). This MSDN blog article (http://blogs.msdn.com/b/avkashchauhan/archive/2011/09/16/whats-new-in-windows-azure-sdk-1-5-each-instance-in-any-role-gets-its-own-ip-address-to-match-compute-emulator-close-the-cloud-environment.aspx) of the microsoft employee Avkash Chauhan describes this behavior as well. After that conclusion I came to the following question: why the hell does the compute emulator (more precisely DevFC.exe) not add the IP of the appropriate role to the binding information of each Website???
I added the IP to each Website by hand and tadaaaaa: every Website can be started without any collisions. The next screenshot demonstrates it with the changed binding information highlighted.
Screenshot: IIS with started Websites
Once again: Why the hell does the emulator not do it for me? I wrote a small static helper method to do the binding extension thing for me on every role start. Maybe someone wants to use it:
public static class Emulator
{
public static void RepairBinding(string siteNameFromServiceModel, string endpointName)
{
// Use a mutex to mutually exclude the manipulation of the iis configuration.
// Otherwise server.CommitChanges() will throw an exeption!
using (var mutex = new System.Threading.Mutex(false, "AzureTools.Emulator.RepairBinding"))
{
mutex.WaitOne();
using (var server = new Microsoft.Web.Administration.ServerManager())
{
var siteName = string.Format("{0}_{1}", Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.CurrentRoleInstance.Id, siteNameFromServiceModel);
var site = server.Sites[siteName];
// Add the IP of the role to the binding information of the website
foreach (Binding binding in site.Bindings)
{
//"*:82:"
if (binding.BindingInformation[0] == '*')
{
var instanceEndpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints[endpointName];
string bindingInformation = instanceEndpoint.IPEndpoint.Address.ToString() + binding.BindingInformation.Substring(1);
binding.BindingInformation = bindingInformation;
server.CommitChanges();
}
else
{
throw new InvalidOperationException();
}
}
}
// Start all websites of the role if all bindings of all websites of the role are prepared.
using (var server = new Microsoft.Web.Administration.ServerManager())
{
var sitesOfRole = server.Sites.Where(site => site.Name.Contains(RoleEnvironment.CurrentRoleInstance.Role.Name));
if (sitesOfRole.All(site => site.Bindings.All(binding => binding.BindingInformation[0] != '*')))
{
foreach (Site site in sitesOfRole)
{
if (site.State == ObjectState.Stopped)
{
site.Start();
}
}
}
}
mutex.ReleaseMutex();
}
}
}
I call the helper method as follows
public class WebRole : RoleEntryPoint
{
public override bool OnStart()
{
if (RoleEnvironment.IsEmulated)
{
AzureTools.Emulator.RepairBinding("Web", "ServiceEndpoint");
}
return base.OnStart();
}
}
I got it!
I have this behavior on three different machines which are all formatted and served with fresh clean windows 8, Visual Studio 2012 and Azure SDK 1.8 and Azure Tools installations recently. So a reinstallation of the Azure SDK and Tools (as Anton suggests) should not change anything. But the cleanliness of my three machines is the crucial point! Anton, do you have Visual Studio 2010 on your machine with at least VS2010 SP 1 installed? I analyzed IISConfigurator.exe with ILSpy and found the code which sets the IP in the binding information of the websites to '*' (instead of 127.255.0.*). It depends on the static property Microsoft.WindowsAzure.Common.Workarounds.BindToAllIpsWorkaroundEnabled. This method internally uses Microsoft.WindowsAzure.Common.Workarounds.TryGetVS2010SPVersion and leads to setting the IP binding to '*' if the SP level of Visual Studio 2010 is smaller than 1. TryGetVS2010SPVersion checks four registry keys and I don't know why but one of the keys exists in my registry und returns the Visual Studio 2010 SP level 0 (I never installed VS2010 on no one of the three machines!!!). As I changed the value of HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\DevDiv\vs\Servicing\10.0\SP from 0 to 10 (something greater 0 should do it) the Azure Emulator starts to set the 127.255.0.* IPs of the roles to the binding information on all of the websites in the IIS and all websites are started correctly.

Resources