If you're spinning up a WCF service for testing in Visual Studio and you get the message "Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost:XXXXX'" then there is a simple 2 minute fix.
General postings on bits and pieces of ASP.net and other Microsoft development that may be of use out there
Tuesday, 20 September 2016
Could not establish trust relationship for the SSL/TLS secure channel with authority XXXX
If you're spinning up a WCF service for testing in Visual Studio and you get the message "Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost:XXXXX'" then there is a simple 2 minute fix.
Thursday, 27 March 2014
Free Training For Life
Wednesday, 13 June 2012
Please support the campaign to save lennox
If you care about animals and are as gobsmacked as me by the groundless adherance to the letter of the unjust Breed Specific Legislation in Belfast then please sign the petition to save lennox - condemned to be destroyed for basically looking like a dog that wouldn't necessarily be dangerous anyway - http://www.petitiononline.com/
http://www.savelennox.co.uk/ for more - please spread the word and try and get this ruling overturned
Tuesday, 12 June 2012
Microsoft conferences online
The conferences do have different focuses, but these days you will normally find something on most subjects at any of the conferences.
Teched (which is running now, at the time I write this post) - this one is normally quite heavy on IT, but with some interesting dev pieces in there
- This year's sessions - http://channel9.msdn.com/Events/TechEd/NorthAmerica/2012
- Archive back to 2008 - http://channel9.msdn.com/Events/TechEd
The Professional Developer Conference (PDC) - the key's in the name - for devs mainly, was the forerunner to Build - Archives from 1991 to 2010 are at http://channel9.msdn.com/Events/PDC
MIX - mainly for designers tho with some dev in there aswell - archives from 2006 to 2011 are at http://channel9.msdn.com/Events/MIX
These are all worth a look through - there are 1000s of hours of the best insight to working with the MS platforms you could possibly hope for.
Enjoy
Sunday, 26 February 2012
Accessing Printer Status using WinSpool in C#
After help from ambience I’ve managed to get the code working to access accurate printer status by using DllImport to access Winspool.drv (as opposed to using WMI, which had very mixed results).
There are 3 key functions you need to be aware of:
- OpenPrinter
- GetPrinter
- ClosePrinter
The GetPrinter function is the one that does the real work we are interested in – accessing the PrinterInfo2 structure that gives you all the information you could possibly want on your named printer – driver, status, configuration, etc
Once you have the PrinterInfo2 you can than use bitwise operators along with known constants to find out the current status of the printer. One thing to note is that to detect whether a printer is marked as offline rather than physically offline you need to check the Attributes rather than Status – I’ll put a followup post shortly with details of a Helper class round the PrinterInfo2 status.
Here’s the code to help you out if, like me you need to get accurate printer info in C#:
//Code written by Mark Middlemist - @delradie
//Made available at http://delradiesdev.blogspot.com
//Interop details from http://pinvoke.net/
using System;
using System.Runtime.InteropServices;
namespace DelradiesDev.PrinterStatus
{
public class WinSpoolPrinterInfo
{
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int OpenPrinter(string pPrinterName, out IntPtr phPrinter, ref PRINTER_DEFAULTS pDefault);
[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool GetPrinter(IntPtr hPrinter, Int32 dwLevel, IntPtr pPrinter, Int32 dwBuf, out Int32 dwNeeded);
[DllImport("winspool.drv", SetLastError = true)]
public static extern int ClosePrinter(IntPtr hPrinter);
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_DEFAULTS
{
public IntPtr pDatatype;
public IntPtr pDevMode;
public int DesiredAccess;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct PRINTER_INFO_2
{
[MarshalAs(UnmanagedType.LPTStr)]
public string pServerName;
[MarshalAs(UnmanagedType.LPTStr)]
public string pPrinterName;
[MarshalAs(UnmanagedType.LPTStr)]
public string pShareName;
[MarshalAs(UnmanagedType.LPTStr)]
public string pPortName;
[MarshalAs(UnmanagedType.LPTStr)]
public string pDriverName;
[MarshalAs(UnmanagedType.LPTStr)]
public string pComment;
[MarshalAs(UnmanagedType.LPTStr)]
public string pLocation;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.LPTStr)]
public string pSepFile;
[MarshalAs(UnmanagedType.LPTStr)]
public string pPrintProcessor;
[MarshalAs(UnmanagedType.LPTStr)]
public string pDatatype;
[MarshalAs(UnmanagedType.LPTStr)]
public string pParameters;
public IntPtr pSecurityDescriptor;
public uint Attributes;
public uint Priority;
public uint DefaultPriority;
public uint StartTime;
public uint UntilTime;
public uint Status;
public uint cJobs;
public uint AveragePPM;
}
public PRINTER_INFO_2? GetPrinterInfo(String printerName)
{
IntPtr pHandle;
PRINTER_DEFAULTS defaults = new PRINTER_DEFAULTS();
PRINTER_INFO_2? Info2 = null;
OpenPrinter(printerName, out pHandle, ref defaults);
Int32 cbNeeded = 0;
bool bRet = GetPrinter(pHandle, 2, IntPtr.Zero, 0, out cbNeeded);
if (cbNeeded > 0)
{
IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded);
bRet = GetPrinter(pHandle, 2, pAddr, cbNeeded, out cbNeeded);
if (bRet)
{
Info2 = (PRINTER_INFO_2)Marshal.PtrToStructure(pAddr, typeof(PRINTER_INFO_2));
}
Marshal.FreeHGlobal(pAddr);
}
ClosePrinter(pHandle);
return Info2;
}
}
}
Thursday, 23 February 2012
Rebinding bug in WinForms ListBox when SelectionMode = None
It appears that there are a couple of issues with WinForms ListBoxes when the SelectionMode is None (certainly in .net 2).
One that is pretty well documented is that if your SelectionMode is None then you can get problems on closing the form (https://connect.microsoft.com/VisualStudio/feedback/details/189700/listbox-selectionmode-none-bug)
One I've just hit on is that if you rebind/refresh a listbox's contents by changing the datasource then the list is cleared and left blank
The workaround is very simple (based on the one from Connect) - before manipulating the DataSource property on the ListBox change the SelectionMode to one of the other values, do your work, then change it back to None
Hope this helps
Wednesday, 3 August 2011
Adding MVC 3 to an asp.net web site
I've been starting to tool up on MVC, and while I won't cover that right now as there's no shortage of coverage on that, I wanted to cover one bit that seems slightly lacking in coverage, which is specifically adding MVC 3 to ASP.Net Websites (not web projects).
The most excellent Mr Hanselman has already done the vast majority of the work for anyone wanting to add mvc to asp.net (and in fact pretty much all of it if you're using a web application) with his AddMvc3ToWebForms Nuget Package
There are however a couple more steps needed to get it working with a web site rather than web project
1) Install the nuget package as normal, either by selecting AddMvc3ToWebForms from the online gallery in Visual Studio's "Add Library Package Reference" option (Tools > Library Package Manager > Add Library Package Reference), or by typing the command Install-Package AddMvc3ToWebForms in the Package Manager Console (Tools > Library Package Manager > Package Manager Console)
When I ran this I got an error at the end but as far as I can tell, this isn't actually a problem, but caused by it not having a csproj file to work with:
PM> Install-Package AddMvc3ToWebForms
'WebActivator (≥ 1.3)' not installed. Attempting to retrieve dependency from source...
Done.
Successfully installed 'WebActivator 1.3.2'.
Successfully installed 'AddMvc3ToWebForms 0.9.1'.
Successfully added 'WebActivator 1.3.2' to extranet.
Successfully added 'AddMvc3ToWebForms 0.9.1' to extranet.
Install-Package : Method invocation failed because [System.__ComObject] doesn't contain a method named 'Add'.
At line:1 char:16
+ Install-Package <<<< AddMvc3ToWebForms
+ CategoryInfo : NotSpecified: (:) [Install-Package], RuntimeException
+ FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PowerShell.Commands.InstallPackageCommand
If you try and compile now it will fail, complaing of not being able to find MvcApplication1. This is because the view (cshtml) files it creates reference a standard namespace (MvcApplication1) that doesn't correspond to the ASP namespace in the created model/controller files. There is also the additional issue that in a web site the 'M&C' files should live under App_Code not in the rool directory.
2a) If you aren't interested in the initial files created by the package then you could simply create Models and Controllers directories under App_Code, delete the ones in the site root, and empty out the Views directory, then get on with your own coding
2b) If you do want to keep the Account/Home/Shared files that have been created then move the Models and Controllers files to App_Code
3) To resolve the namespace issue open up ChangePassword.cshtml, LogOn.cshtml, Register.cshtml in Views\Account and remove the 'MvcApplication1.' from the @model reference at the top
You should now be ready to roll - Enjoy
Friday, 11 March 2011
Breaking down 'google' sitemaps
Once you start databinding your sitemaps, especially if you have as much data as we do on presalesadvisor is to break the sitemap down, using a master index map. These look a lot like the normal sitemaps, but uses a sitemapindex top level element in place of the urlset, and sitemap in place of url. Each location (sitemapindex - sitemap - loc) should then point to individual sitemap files which google, etc will then drill down in to.
A good example of where this would be useful is on presalesadvisor, where there is a huge quantity of data being generated in multiple regional sets. When generated all in one big sitemap file the load time is huge, and risking timeout. Instead we set up our objectdatasources with a querystring parameter of the region code (e.g. en-GB, en-US) and then link to these subsets from the main sitemapindex. With this simple change load times and server load are greatly reduced (which is more important these days from the SEO angle with google taking load times in to account in their ranking algorithms), and we have an all round win.
The sitemaps themselves remain exactly the same as before, and the new sitemapindex looks like this:
<?xml version="1.0" encoding="UTF-8" ?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>http://public.presalesadvisor.com/Sitemap/XmlSiteMap.aspx?regionID=en-US</loc>
</sitemap>
<sitemap>
<loc>http://public.presalesadvisor.com/Sitemap/XmlSiteMap.aspx?regionID=en-GB</loc>
</sitemap>
</sitemapindex>
In terms of function all you do differently when logged into your google site admin is add the new SiteMapIndex url as your sitemap rather than any of the actual individual sitemaps
Thursday, 20 January 2011
Step by step guide to installing the Surface SDK on 64 bit windows
To get up and running you will need the following:
XNA 2 Redist
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=15fb9169-4a25-4dca-bf40-9c497568f102&displaylang=en
Windows SDK
http://msdn.microsoft.com/en-us/windows/bb980924
Surface SDK 1.0 SP1
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=3db8987b-47c8-46ca-aafb-9c3b36f43bcc&displaylang=en
1) Once you have the above, install the XNA 2 Framework and the Windows SDK
2) Go into the windows sdk bin directory (probably C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bin or similar) and run Orca.msi
3) Run Orca and open the file SurfaceSDKWE.msi
- Locate LaunchConditions in the tables list on the left
- Delete the rows 'Installed OR NOT VersionNT64'and 'Installed OR VISTASKU<>"Starter"'
Also, if you are using Visual Studio 2010 and do not have any installation of Visual Studio 2008 then you will want to also delete the following:
-'Installed OR (VS2008SPLEVEL AND VS2008SPLEVEL >= "#0") OR (VCSEXP2008SPLEVEL AND VCSEXP2008SPLEVEL >= "#0")'
-'Installed OR (VS2008SPLEVEL AND VS2008CSPROJSUPPORT) OR VCSEXP2008SPLEVEL'
Save the file and close orca
4) In a command prompt extract the msi file either using 'msiexec /a SurfaceSDKWE.msi /qb TARGETDIR=C:\Temp\SurfaceSDKWEExtract'
5) Open the msi in the extract directory using orca and remove the launch conditions again
5.5 - optional) If for whatever reason you are not using the visual studio command prompy set your machine's PATH environment variable to include the windows sdk bin directory, or alternatively prefix the corflags commands below with the full path
6) Run an administrator level command prompt and navigate to the directory you extracted the msi to, then in to \Microsoft Surface\v1.0\ and run
'corflags setupcustomaction.exe /32bit+ /force'
7) Run the installer you have just modified
8) Using the command prompt navigate through the install directory and its children and run the corflags command against each of the executables
You should now be able to run the demos etc, but if you want to build and run the code samples yourself you will need to ensure that the project settings are targetting x86 CPUs explicitly
9) HAVE FUN
Tuesday, 18 January 2011
It takes all sorts
It really does take all sorts
Sunday, 5 December 2010
Using Linq to remove duplicate data from a DataTable
In response to a question on experts exchange I just wanted to do a quick post on data cleanup using Linq
Linq has a lot of very useful operations that can be used to reduce the complexity of array (or dataset) operation.
In this instance the operator .Distinct() can be used to remove duplicates in a datatable, with a small priviso:
If you call the method on the datatable (using the call .AsEnumerable() to get it in to a form you can work with in linq) with no parameters you will find that it returns all rows - this is because by default it does an object comparison, and of course all the records have their own memory address, and therefore are considered to be different. The trick is to tell it to use the default DataRowComparer which will get it to do a column by column value check.
One final point to watch out for is in getting the data back in to datatable - remember that datasets/tables/rows are reference types, so clearing down the tabe will actually cause problems, so the trick is to take a copy of the datatable, clear the original, operate on the copy, then reimport the rows to the cleared down table.
All put together, the following function will handle this for you:
/// <summary>/// Removes duplicate rows from the target table/// </summary>/// <param name="sourceDataSet">Dataset containing the table to operate on</param>/// <param name="targetTableName">Name of the table to operate on</param>
{public void GetUniqueRows(DataSet sourceDataSet, String targetTableName) //Check there is data to operate on
//Take a copy of the table so clearing does not affect the operation
//Run the distinct operation
//Clear all data from the target table sourceDataSet.Tables[targetTableName].Clear();
//Re-import the distinct rows to the 'live' table
{
sourceDataSet.Tables[targetTableName].ImportRow(DistinctRow);
}
} foreach (DataRow DistinctRow in OutputRows) DataRow[] OutputRows = (from rows in OperatingData.AsEnumerable() select rows).Distinct(System.Data.DataRowComparer.Default).ToArray() as DataRow[]; DataTable OperatingData = sourceDataSet.Tables[targetTableName].Copy(); if (sourceDataSet.Tables[targetTableName].Rows.Count == 0) return;
Friday, 3 December 2010
If you've found any of this information useful
Happy Staffie Rescue (http://www.happystaffierescue.org.uk/), based in the west midlands, are a breed rescue for Staffordshire Bull Terriers - a much maligned but very loving breed (we have 3 of our own).
If you can spare even a small amount this would help make a big difference for some wonderful dogs that really do deserve much better than the hands that life has dealt them.
You can donate online via http://www.happystaffierescue.org.uk/id123.html
Merry Christmas
Monday, 29 November 2010
Vertical GridViews in ASP.net - Part 2c: Plumbing in the custom rendering
The key function you will need to work in is an override to the RenderChildren function in your inherited gridview (protected override void RenderChildren(HtmlTextWriter writer)).
First off, you need to create a dictionary of your custom row renderers, one for each row in the controls Rows collection (of type GridViewRowCollection), indexed by the original row id (or a list of them in the same order as the original collection. As set up previously, the 'row renderer' is constructed by passing in the gridviewrow.
As you're overriding the child controls the one drawback is that you have to manually set up that table, using the htmlwriter to output the various rendering parameters:
if(this.BorderWidth != null)
writer.AddAttribute(HtmlTextWriterAttribute.Border, this.BorderWidth.ToString());
writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing, this.CellSpacing.ToString());
writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, this.CellPadding.ToString());
if (this.CssClass != null)
writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass.ToString());
writer.RenderBeginTag(HtmlTextWriterTag.Table);
then the important bit - for the moment we'll go with the simplified case that you are displaying all your datarows in one long row (I'll cover wrapping in a future post).
Firstly, iterate over the columns in the GridView's Columns collection (of type DataControlFieldCollection) - there is one entry in this collection for every field (BoundField,TemplateField, etc.) specified in the markup using the gridview.
Within this loop you then need to:
- Tell the html writer to write out the <TR> tag:
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
- Loop over the rows in renderer list/dictionary, and within that call your renderer's custom cell Render Method:
Renderers[RowIndex].Render(writer, ColumnIndex, IsHeader);
- Tell the htmlwriter to write out the closing </TR> tag:
writer.RenderEndTag();
After the loops you then need to tell the html writer to write the closing </TABLE> tag with a final call to writer.RenderEndTag()
With the code detailed about you now have the full basic solution. I will post more on some additions that you will most likely want - wrapping, empty cell handling, and Custom CSS properties, all of which are used in the featured product grids on http://public.presalesadvisor.com/ - but hopefully this is enough to get you started.
Friday, 26 November 2010
Databound google sitemaps with repeaters in asp.net
The basic principle can be used for anything, but one use we've put it to on the Pre-Sales Advisor site is to generate a databound xml sitemap for google submission (for full details of the format see the official site at http://www.sitemaps.org/).
In most data driven websites the data pages you really want found are displayed by calling a standard page with the correct querystring (e.g. http://public.presalesadvisor.com/Common/BuildByFamily.aspx?identity=2141&dso=en-US for Bladecenter HS22, http://public.presalesadvisor.com/Common/BuildByFamily.aspx?identity=3013&dso=en-US for system x3630 M3s). As long as you can pull out a list of valid identities through a datasource then all you need to do is set up your repeater templates as follows:
<HeaderTemplate>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:image="http://www.sitemaps.org/schemas/sitemap-image/1.1"
xmlns:video="http://www.sitemaps.org/schemas/sitemap-video/1.1">
</HeaderTemplate>
<FooterTemplate>
</urlset>
</FooterTemplate>
<ItemTemplate>
<url>
<loc><%# Server.HtmlEncode(String.Format("http://www.yoursite.com/page.aspx?id={0}", DataBinder.Eval(Container.DataItem, "IDENTITYCOLUMN")))%></loc>
</url>
</ItemTemplate>
and there you have it. For an example of what it comes out like have a look at the xml site map linked from http://public.presalesadvisor.com/sitemap.aspx (incidentally, if you have a look at the global part map that uses basically. the same data sources and repeater setup).
Thursday, 25 November 2010
Vertical GridViews in ASP.net - Part 2b: Cell level rendering a GridViewRow
- A class variable to store the GridViewRow this is wrapping around
- A constructor that takes in a GridViewRow and assigns it to the class variable
- A render method that takes in a HTMLTextWriter, the index of the cell you want to render within the row, and a flag to indicate if this is to be rendered as a ‘header cell’ (more on the last in a post to follow)
If you’re not needing to output the cell as a header (i.e. render as a TH rather than a TD) all you need to do now is call the cell’s RenderControl method, passing in the HtmlTextWriter
If you do need to render as a header cell things aren’t quite as simple – header cells are actually set up during CreateChildControls as a different type - DataControlFieldHeaderCell rather than DataControlFieldCell.
The simplest solution we found was creating a new DataControlFieldHeaderCell and manually copying the properties that we were interesting in preserving from the original cell (in our case CssClass, HorizontalAlign, and VerticalAlign), and then reassign the child controls from the original cell to the new cell:
while (OriginalCell.Controls.Count > 0)
Once this is done call the header cell’s RenderControl as before.
I’ll leave it there for now, but will be post again soon with how to plumb this in to the standard control rendering
Saturday, 20 November 2010
Easy guide to databound RSS feeds in Asp.Net
I'd like to empasise first off this is in no way a method I can take credit for, but I wanted to pass it along to help out any dev's out there who get the fateful brief "oh, before we put this live can you just stick an RSS feed in"
If you've done any reading then you'll know that RSS (Really Simple Syndication) is based around a specific XML format. The key to simple databound RSS is to use a standard page and standard controls, but writing out XML rather than HTML markup.
To make the page work as a feed you need to do the following:
-Delete out all preentered content except for the @Page directive
-In the @Page directive include the attribute ContentType="text/xml"
-Include a standard datasource that will output the data that you want to publish
-Include an asp repeater with the DataSourceID set to your datasource, and with the following content:
HeaderTemplate:
<rss version="2.0">
<channel>
<title>FEED NAME</title>
<link>URL THAT THE FEED WILL BE PUBLISHED TO</link>
<description>DESCRIPTION OF THE FEED</description>
FooterTemplate:
</channel>
</rss>
ItemTemplate:
<item>
<title><%#DataBinder.Eval(Container.DataItem, "POST TITLE COLUMN")%></title>
<description><%#DataBinder.Eval(Container.DataItem, "POST TEXT SUMMARY COLUMN")%></description>
<link>CLICK-THROUGH URL</link>
<pubdate><%#DataBinder.Eval(Container.DataItem, "ARTICLE TIMESTAMP COLUMN")%></pubdate>
</item>
That's all it takes - Enjoy :)
Tuesday, 16 November 2010
Vertical GridViews in ASP.net - Part 2a : The general solution
There are 2 main ways you would do this:
1) Create a new control that inherits from GridView and override the methods involved in rendering
or
2) Use a Control Adapter to provide custom rendering
Personally I don't like the idea of method 2 - unless I'm misunderstanding something here it means rely on the browser capability file to apply, and it generally seems that even if we got the required rendering the application of it would be less precise than explicity specifiying which control you are using.
For our custom control - VerticalGridView - the point where we intercept the standard GridView behaviour is function RenderChildren (protected void RenderChildren(HtmlTextWriter writer)).
In a standard GridView this would render to the output Html writer:
- The table header with attributes set based on the properties set on the grid view
- One Table Row (TR) per DataRow in the source data within the parent table (with attributes set based on the properties set on the grid view)
- One Table Cell (TH/TD) per ItemTemplate specified in the markup, rendered within the parent row (with cell type and attributes set based on the properties in the ItemTemplate)
- Closing table tags
Note that this is not a canonical representation of the standard functionality - just detail appropriate to the level that we needed to control for our purposes. For a full view of the code then I'd recommend downloading the free and wonderful RedGate Reflector and disassembling the method in System.Web.UI.WebControls.GridView, and GridViewRow in System.Web.dll
So this is where we rewrite the rules. How exactly we do that to follow shortly
Just to mention to those who don't already know, the vertical grids described here can be seen in action on the front page of http://public.presalesadvisor.com/
Incedentally, just to thank the GiantCodeMonkey himself for the inspiration for the solution, and the permission to write it up
Tuesday, 26 October 2010
Vertical GridViews in ASP.net - Part 1 : The problem
The obvious web control for this sort of data presentation would be a gridview - they render out as HTML tables, and a lot of standard event hookup code already existed in the codebase for use elsewhere. Here we hit the problem; gridviews render out sequentially with a table row per data item, we wanted it to have a column per data item, and of course HTML tables have no conept of a 'column' of data.
This meant that we needed to find a way of presenting data that:
- rendered each data item vertically
- aligned each section of data horizontally
- used the standard gridview event model
After a considerable amount of research online the general consensus seemed to be to 'hack' the data source to rotate the dataset - crosstab style - or.... give up. Neither of these were really an options so what I'll try and detail in the following posts is how we got the grids as they now appear on the font page of http://public.presalesadvisor.net/
Intro - The Dev Blog
Hopefully someone out there will find something on here at least a little useful.
To kick off shortly, vertical (product comparison style) gridviews in asp.net as implemented on http://public.presalesadvisor.net/