Here is a bare bones demonstration (4 minutes) showing you how to create a standalone class library of a WebApi controller, then hosting the controller in Microsoft's OWIN (in IIS). This is done using Visual Studio 2013 Update 3.
The video can be watched here: YouTube Watch
The source can be downloaded here: Download Source
What do you think?
Just some random development ramblings mostly related to the Microsoft .NET platform.
Showing posts with label IIS. Show all posts
Showing posts with label IIS. Show all posts
Thursday, October 23, 2014
Sunday, June 9, 2013
IIS URL Rewrite non-www site to www
Use the IIS URL Rewrite module to route a site without "www" prefix to your standard "www" site. Below is the web.config section to do this.
<system.webserver>
<rewrite>
<rules>
<rule name="Redirect to WWW" stopprocessing="true">
<match url="(.*)">
<conditions>
<add input="{HTTP_HOST}" negate="true" pattern="^www\.([.a-zA-Z0-9]+)$">
</add>
</conditions>
<action appendquerystring="true" type="Redirect" url="http://www.{HTTP_HOST}/{R:0}">
</action></match></rule>
</rules>
</rewrite>
</system.webserver>
Thursday, October 1, 2009
Server 2008 R2 / ApplicationPoolIdentity / Databases
I recently set up a new website on a Windows Server 2008 R2 computer running IIS 7.5 and SQL Server 2008. The new site would not run...wouldn't even start (.NET security issus, database login error). After some painful investigation on the issues, I encapsulated the steps to correctly use IIS 7.5's new ApplicationPoolIdentity support and allow access to a SQL Server 2008 database.
Microsoft will continue to cramp down on security and the use of ApplicationPoolIdentity is the default settings for a new website (so I'm blogging this to help others and to remind myself).
To the best of my knowledge, here are the steps to get your site up and running on 2008 R2 (if you have any corrections or feedback, please comment):
Whew!
Microsoft will continue to cramp down on security and the use of ApplicationPoolIdentity is the default settings for a new website (so I'm blogging this to help others and to remind myself).
To the best of my knowledge, here are the steps to get your site up and running on 2008 R2 (if you have any corrections or feedback, please comment):
1) Using IIS, select “Application Pools”. Right-click the pool to modify and
choose “Advanced Settings”. In the “Process Model” section:
a. Verify “Identify” is set to ApplicationPoolIdentity.
b. Verify “Load User Profile” is set to true.
2) Using IIS, select the site to modify. In the IIS section, double-click
“Authentication”. Next “Edit” the “Anonymous Authentication” name and verify
“Application pool identity” is chosen.
3) Using SQL Studio Management Studio, select “Security”, then “Logins”. Add
“New Login” using:
a. Set “Login name” to “IIS AppPool\yourIISSiteName”.
b. Select “Windows authentication” (don’t worry that this doesn’t resemble a
real account on the computer; click OK).
4) Optional for security flexibility on the site files:
a. Using Windows Explorer, right-click the site directory and choose
“Properties”. Select the “Security” tab and choose “Add”.
b. In the “Enter the object names select” box, enter
“IIS AppPool\yourIISSiteName”. Click OK.
c. Before leaving the “Permissions” dialog, customize the permissions for the
new account (read, write, execute, etc.).
Whew!
Monday, September 8, 2008
Zip XML in memory for Web Service transport (SharpZipLib)
Here is a full test program that demonstrates how to use SharpZipLib to zip an XElement into a byte array. This allows you to transfer large XML items over web services, and then unzip then on the web service side. I included two methods to unzip, both back to an XElement and to an XML file. IIS 6 does allow compression as well, but the reason I had to have the functionality below was that a PC client application was required to send a host web service a large set of XML (rather than the host sending the client XML).
using System;
using System.IO;
using System.Xml.Linq;
using ICSharpCode.SharpZipLib.Zip;
namespace ConsoleTest
{
class Program
{
static void Main(string[] args)
{
new Program().Run(args);
}
private void Run(string[] args)
{
// create some xml
XElement xml = XElement.Parse("<xml><element>whatever</element></xml>");
// zip xml
string startXml = xml.ToString();
byte[] bytes = ZipContent(xml, "TestXML");
// unzip xml
xml = UnzipContent(bytes);
string endXml = xml.ToString();
// sanity check
System.Diagnostics.Debug.Assert(startXml == endXml);
}
/// <summary>
/// Convert XML to zipped byte array.
/// </summary>
/// <param name="xml">XML to zip.</param>
/// <param name="entryName">The zip entry name.</param>
/// <returns>A byte array that contains the xml zipped.</returns>
private byte[] ZipContent(XElement xml, string entryName)
{
// remove whitespace from xml and convert to byte array
byte[] normalBytes;
using (StringWriter writer = new StringWriter())
{
xml.Save(writer, SaveOptions.DisableFormatting);
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
normalBytes = encoding.GetBytes(writer.ToString());
}
// zip into new, zipped, byte array
using (Stream memOutput = new MemoryStream())
using (ZipOutputStream zipOutput = new ZipOutputStream(memOutput))
{
zipOutput.SetLevel(9);
ZipEntry entry = new ZipEntry(entryName);
entry.DateTime = DateTime.Now;
zipOutput.PutNextEntry(entry);
zipOutput.Write(normalBytes, 0, normalBytes.Length);
zipOutput.Finish();
byte[] newBytes = new byte[memOutput.Length];
memOutput.Seek(0, SeekOrigin.Begin);
memOutput.Read(newBytes, 0, newBytes.Length);
zipOutput.Close();
return newBytes;
}
}
/// <summary>
/// Return zipped bytes as unzipped XML.
/// </summary>
/// <param name="bytes">Zipped content.</param>
/// <returns>Unzipped XML.</returns>
private XElement UnzipContent(byte[] bytes)
{
// unzip bytes into unzipped byte array
using (Stream memInput = new MemoryStream(bytes))
using (ZipInputStream input = new ZipInputStream(memInput))
{
ZipEntry entry = input.GetNextEntry();
byte[] newBytes = new byte[entry.Size];
int count = input.Read(newBytes, 0, newBytes.Length);
if (count != entry.Size)
{
throw new Exception("Invalid read: " + count);
}
// convert bytes to string, then to xml
string xmlString = System.Text.ASCIIEncoding.ASCII.GetString(newBytes);
return XElement.Parse(xmlString);
}
}
/// <summary>
/// Save zipped bytes as unzipped file.
/// </summary>
/// <param name="bytes">Zipped content.</param>
/// <param name="path">File path to save unzipped XML.</param>
private void UnzipContent(byte[] bytes, string path)
{
// unzip bytes into unzipped byte array
using (Stream memInput = new MemoryStream(bytes))
using (ZipInputStream zipInput = new ZipInputStream(memInput))
using (BinaryWriter writer = new BinaryWriter(File.Create(path)))
{
ZipEntry entry = zipInput.GetNextEntry();
int count;
byte[] input = new byte[1024 * 10];
while ((count = zipInput.Read(input, 0, input.Length)) > 0)
{
writer.Write(input, 0, count);
}
}
}
}
}
Saturday, March 29, 2008
This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.
Description:
When you try to access a WCF service hosted in IIS, you get the following error:
This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.
Context:
You have a website hosted in IIS and the site has multiple host headers defined for the site (e.g. www.domain.com, domain.com).
Fix:
There doesn’t appear to be a nice workable solution for this as of VS 2008 initial release on .NET 3.5. The only “hack” found out there is to define a new Factory for the service.
Step 1:
Some web articles had you also creating a new host derived from ServiceHost, but that is not needed.
Step 2:
Modify the .svc file on the site hosting the service (not the .svc in Visual Studio):
<%@ ServiceHost Service="Foo.Service1" Factory="Foo.CustomHostFactory" %>
The above .svc content may also include the language and debug specifiers.
When you try to access a WCF service hosted in IIS, you get the following error:
This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.
Context:
You have a website hosted in IIS and the site has multiple host headers defined for the site (e.g. www.domain.com, domain.com).
Fix:
There doesn’t appear to be a nice workable solution for this as of VS 2008 initial release on .NET 3.5. The only “hack” found out there is to define a new Factory for the service.
Step 1:
namespace Foo
{
public class CustomHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(
Type serviceType,
Uri[] baseAddresses)
{
// Specify the exact URL of your web service from the config file:
// e.g. http://www.domain.com/service/myservice.svc
Uri webServiceAddress =
new Uri(ConfigurationManager.AppSettings["ServiceUri"]);
ServiceHost webServiceHost =
new ServiceHost(serviceType, webServiceAddress);
return webServiceHost;
}
}
}
Some web articles had you also creating a new host derived from ServiceHost, but that is not needed.
Step 2:
Modify the .svc file on the site hosting the service (not the .svc in Visual Studio):
<%@ ServiceHost Service="Foo.Service1" Factory="Foo.CustomHostFactory" %>
The above .svc content may also include the language and debug specifiers.
Can't add web reference in VS 2008 due to computer name being used for schemaLocation
Description:
You can’t add a web reference using Visual Studio 2008 for a WCF service since the WSDL is using the computer name rather than the service address. If you develop using "localhost" as the service name this is NOT an issue.
Context:
You have a computer/website with more than one IP address and are developing a WCF web service on one of the extra IP addresses (Site A).
Issue:
When you use Visual Studio 2008 to add a reference to a web service on Site A, you will get an error something like:
The document at the url http://192.168.0.54:8000/abcService.svc was not
recognized as a known document type.
The error message from each known type may help you fix the problem:
- Report from 'WSDL Document' is 'The document format is not recognized (the
content type is 'text/html; charset=utf-8').'.
- Report from 'DISCO Document' is 'There was an error downloading
'http://192.168.0.54:8000/abcService.svc?disco'.'.
- The request failed with HTTP status 404: Not Found.
- Report from 'XML Schema' is 'The document format is not recognized (the
content type is 'text/html; charset=utf-8').'.
If you look manually enter the service url in a browser for the service at the IP address (e.g. 192.168.0.54), you will see in the XML WSDL that it is trying to import schemas (schemaLocation) using the computer name, not the service address (192.168.0.54).
Fix:
I fixed this by just making sure I entered the IP address as the host header in IIS. Then the IP address was used rather than the computer name for all WSDL url references.
You can’t add a web reference using Visual Studio 2008 for a WCF service since the WSDL is using the computer name rather than the service address. If you develop using "localhost" as the service name this is NOT an issue.
Context:
You have a computer/website with more than one IP address and are developing a WCF web service on one of the extra IP addresses (Site A).
Issue:
When you use Visual Studio 2008 to add a reference to a web service on Site A, you will get an error something like:
The document at the url http://192.168.0.54:8000/abcService.svc was not
recognized as a known document type.
The error message from each known type may help you fix the problem:
- Report from 'WSDL Document' is 'The document format is not recognized (the
content type is 'text/html; charset=utf-8').'.
- Report from 'DISCO Document' is 'There was an error downloading
'http://192.168.0.54:8000/abcService.svc?disco'.'.
- The request failed with HTTP status 404: Not Found.
- Report from 'XML Schema' is 'The document format is not recognized (the
content type is 'text/html; charset=utf-8').'.
If you look manually enter the service url in a browser for the service at the IP address (e.g. 192.168.0.54), you will see in the XML WSDL that it is trying to import schemas (schemaLocation) using the computer name, not the service address (192.168.0.54).
Fix:
I fixed this by just making sure I entered the IP address as the host header in IIS. Then the IP address was used rather than the computer name for all WSDL url references.
Tuesday, January 22, 2008
UltiDev Cassini Web Server for ASP.NET Applications
This is a free standalone web server for .NET 1.1 and .NET 2.0.
http://www.ultidev.com/products/Cassini/index.htm
http://www.ultidev.com/products/Cassini/index.htm
Subscribe to:
Posts (Atom)
Can't RDP? How to enable / disable virtual machine firewall for Azure VM
Oh no! I accidentally blocked the RDP port on an Azure virtual machine which resulted in not being able to log into the VM anymore. I did ...
-
Here is a full test program that demonstrates how to use SharpZipLib to zip an XElement into a byte array. This allows you to transfer larg...
-
Don't want Office 2007 installed on your web server to access Excel 2007 content? Here is a Visual Studio C# solution that demonstrates ...