mandag den 23. september 2013

Contact web api from InfoPath Designer 2013

I was having some trouble getting values from my home-brewed web api into a InfoPath Designer 2013 form, so I wanted to document the solution for those of you out there perhaps struggling with this as well.

I was calling a simple 'Hello World'-web api that would return a string. My simple aip looks like this:


namespace ADlookup.Controllers
{
/* model */
public class employee
{
public string employeeId { get; set; }
public string bossId { get; set; }

}


public class ADLookupController : ApiController
{
[HttpGet]
public employee getNearestBossId([FromUri] string id)
{
return new employee()
{
employeeId = id,
bossId = id
};

}
}
}


However, upon calling this api in InfoPath Designer 2013, I got the following error message:



... to indicate the xml structure is invalid.

I didn't get it - when I called the service directly from my browser, valid xml was returned!:



The problem, as it turned out, was of course the one that as opposed to the xml displayed by my browsers, the InfoPath Designer application - correctly - retrieved the data by way of json, the web api's default MO.

So, in order to serve up only XML, for InfoPath to agree with, we'll strip away the web api's possibility of serving up json altogether. Modify your WebApiConfig to resemble the below, though of course take into consideration the routes you have for your own app:


public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

// tbe below must be enabled if this rest service is used with infopath designer 2013 - it only accepts xml data.
// thus we'll remove the json return type
var formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Remove(formatters.JsonFormatter);

}
}


Now, as we re-publish the web api service, we can try once more the url in InfoPath, which will now allow us to proceed to the next step:


Intriguingly, on a completely different note, the 'get data from http rest service' workflow component in Sharepoint Designer 2013 works off JSON, as opposed to XML! But that's a blog-entry for another rainy day.

Hope this helps someone, anyone,

thanks for reading.

torsdag den 5. september 2013

Prevent browser caching of css and javascript files

A modern browser will attempt to cache content as best it can, to make for a better end-user experience. This works well, but we may run into issues when we deploy a set of different files to the server, yet the client browser insists on serving up the old ones out of its cache.

So here's a tip on how to force the client browser to reload newly deployed files. You can use this with any kind of content file served over an http connection, be it css-files, javascript files, you name it.

The trick is to add an updated querystring value to the content url. For example, instead of



< link media='screen and (max-width: 2560px)' href="~/Content/Site.css" rel="stylesheet" />


... we go ...


< link media='screen and (max-width: 2560px)' href="~/Content/Site.css?v=1.0.4034.343343" rel="stylesheet" />


... instead. With each deployment, the 'v' value changes, which will force the client into retrieving a new version of the file on the server.

I'm myself adding the assembly version into the url. I'm speficially doing this, which works with the ASP.NET MVC framework:


 @{
        string versionId = System.Reflection.Assembly.GetAssembly(typeof(timeRegistrering.Web.Controllers.HomeController)).GetName().Version.ToString();
    }

    < link media='screen and (max-width: 2500px)' href="~/Content/Site.css?v=@{@versionId}" rel="stylesheet" />


The above will render as follows into the browser:


  < link media='screen and (max-width: 2500px)' href="/Content/Site.css?v=1.0.4996.19123" rel="stylesheet" />


As the assembly version changes with every build or publish, the url will change accordingly - and the content will be retrieved 'fresh' from the server, as now the client can no longer find the old version with a different version number.

In order to make your assembly version number auto-increment, you'll want to change the following lines in your 'assemblyInfo.cs' file (as found in the 'Properties' folder in your project):



// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.1")]
[assembly: AssemblyFileVersion("1.0.0.1")]


Should be changed to:


  // You can specify all the values or you can default the Revision and Build Numbers 
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("1.0.*")]


The asterix '*' sign will be replaced with the assembly number automatically, to increment on each build/publish.

HTH.

tirsdag den 3. september 2013

Force Internet Explorer compatibility mode off

The Internet Explorer compatibility-mode is a rendering mode to suit older web-pages, typically below and including IE8. They're usually associated with Intranet-sites, in which legacy components often abounds.

To a web-developer it can be hugely frustrating - I know for me it certainly is - to develop that which beyond your control renders horribly in an otherwise 'healthy' IE browser.

The fix - apart from using a different browser, not always a suitable solution - is to include the following meta-tag in the page header section.


< meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" >


The above MUST be the very first meta-tag included within the header section, or you risk the chance of it not working to your satisfaction. As you include it, and browse to the web page with compatibility mode turned on, the tag will force your IE to load the page with the rendering engine pertaining to the browser itself, and not some legacy rendering instead.

HTH

mandag den 26. august 2013

Generating n number of GUID's with a TSQL query


Self-explanatory title, here's the snippet:


DECLARE @i int = 0
DECLARE @tmp_Accounts TABLE (
Id UniqueIdentifier
)

WHILE @i < 24 BEGIN
    SET @i = @i + 1
    
 INSERT INTO @tmp_Accounts (Id)
SELECT newid();
END

select * from @tmp_Accounts

HTH

tirsdag den 6. august 2013

Image orientation of images uploaded via asp.net fileupload control

Even though the pictures you take with your smartphone or such are in portrait orientation, when you transfer them to other systems you can't be sure their orientation will come out right. This happened to me with my iPhone: images I took when uploaded via the fileUpload control were presented in a landscape fashion, despite being shot in the portrait orientation.

The trick in getting the images back to normal is to read the EXIF orientation information off the images's property list. In the below I'll demonstrate how to do this:



byte[] imageData = new byte[fileUpload.ContentLength];
fileUpload.InputStream.Read(imageData, 0, fileUpload.ContentLength);

MemoryStream ms = new MemoryStream(imageData);
Image originalImage = Image.FromStream(ms);


if (originalImage.PropertyIdList.Contains(0x0112))
{
int rotationValue = originalImage.GetPropertyItem(0x0112).Value[0];
switch (rotationValue)
{
case 1: // landscape, do nothing
break;

case 8: // rotated 90 right
// de-rotate:
originalImage.RotateFlip(rotateFlipType: RotateFlipType.Rotate270FlipNone);
break;

case 3: // bottoms up
originalImage.RotateFlip(rotateFlipType: RotateFlipType.Rotate180FlipNone);
break;

case 6: // rotated 90 left
originalImage.RotateFlip(rotateFlipType: RotateFlipType.Rotate90FlipNone);
break;
}
}



As always, I hope this helps someone.

onsdag den 3. juli 2013

Linq-to-sql enums support


I don't much like it when I must specify hard-coded values into my code. It can be a debugging nightmare, furthermore it looks ghastly. Microsoft's Sql Server OR-mapper linq-to-sql, which I like very much, unfortuantely do not have built-in designer support for generating enums from lookup-tables, which has previously found me doing that hard-coding I do not like to do. Well, no more - look on.

Consider the examples database-tables:


The 'periodStatusId' field is the one that I would ideally want to fill in as ...


myObject.periodStatusId = periodStatusIdEnum.OpenedStatus


... as opposed to ...


myObject.periodStatusId = databaseContext.PeriodStatus.Single( foo => foo.Description.Equals("Opened"));


Well there's a will and a way. What we can do is pre-define an enum and alter our database-context to reflect it. So, in your database-layer, define an enum and copy its values from the database. Like this:


public enum PeriodStatusEnum
{
ClosedByUser = 1,
ClosedBySystem = 2,
ReOpenedByUser = 3
}


Above, the integer corresponds to the auto-incrementing interger id of the lookup-table, the text corresponds to the description field.

It, well, it sucks, to have to pre-define the enumeration. Much preferred would be to do this in the designer, but that's not possible with linq-to-sql. So pre-define it we do, in the know that at least this will be a few hundred percent better than going hard-code style.

Now the enum has been created, we'll refer to this instead of the database's native type in the datacontext. Change both the lookup-table's and the referencing table's field types to your enum, pre-fixed with a 'global::' value, i.e. global::yourNamespace(s).periodStatusEnum. Like so:


That's it - now you can use your enumeration as opposed to actively looking up the value. Like this:


TidsRegPeriode period = new TidsRegPeriode();

// populate field by referencing your enumeration
period.periodeStatusId = timeRegistrering.Domain.PeriodStatusEnum.ReOpenedByUser;

... other fields populated...

dbContext.TidsRegPeriodes.InsertOnSubmit(period);
dbContext.SubmitChanges();


Again, it would be tremendously better if we could specify enums in the designer. But we can't - so this is a heck of a lot better.

fredag den 14. juni 2013

Razor calendar table

If you need to build a calendar-table in Razor, look no further, here's a snippet that'll accomplish just that:



@{
System.Globalization.GregorianCalendar cal = new System.Globalization.GregorianCalendar();

var firstDayInMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
int daysInMonth = cal.GetDaysInMonth(DateTime.Now.Year, DateTime.Now.Month);

DayOfWeek firstWeekday = cal.GetDayOfWeek(firstDayInMonth);
var dayNo = (int)firstWeekday;
int daysInMonthCounter = 1;
}

<table id="timeRegCalendarTable">
<thead>
<tr>
@for (int i = 0; i <= 6; i++)
{
<td>@CultureInfo.CurrentCulture.DateTimeFormat.DayNames[i]</td>
}
</tr>
</thead>
<tbody>
@while (daysInMonthCounter <= daysInMonth)
{
<tr>
@for (int j = 0; j <= 6; j++)
{
if (j == dayNo && daysInMonthCounter == 1)
{
<td>@daysInMonthCounter</td>
daysInMonthCounter++;
}
else
{
if (daysInMonthCounter > 1 && daysInMonthCounter <= daysInMonth)
{
<td>@daysInMonthCounter</td>
daysInMonthCounter++;
}
else
{
<td> </td>
}
}
}
</tr>
}
</tbody>
</table>


Hope it'll save you a half an hour.