Take a look at the following mvc csharp code:
Response.AddFileDependency(filename)
Response.Cache.SetETagFromFileDependencies();
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetMaxAge(TimeSpan.FromHours(1));
return File(filename, "video/mp4")
My intension of this was. Please cache this file for one hour (SetMaxAge) and then check if the file is still valid (SetEtagFromFileDependancy) and if it is then cache it again for one hour.
However, it turns out that MVC thinks different :-). When the item is expired MVC returns status code 200 even though the clients submits a matching If-None-Match header. In such cases the webserver is allowed to respond with 304 and update the item with new information passed in the response header.
It could be that I have forgotten something in the code above but the following is the workaround I created for this situation. It needs a custom etag to use so you cannot make use of SetETagFromFileDependencies. The method basically does a Etag comparison and responds with a 304 if they match. If they do not match the method returns null but has set the above mentioned headers.
ActionResult EtagFix(string etagResponse, HttpCacheability cachability, TimeSpan maxAge)
{
var cache = Response.Cache;
cache.SetETag(etagResponse);
cache.SetCacheability(cachability);
cache.SetMaxAge(maxAge);
if (!etagResponse.Equals(Request.Headers["If-None-Match"])) return null;
Response.StatusCode = 304;
Response.StatusDescription = "Not Modified";
return new EmptyResult();
}
This method should be pasted as a method in your controller and then it should just work. The reason that I return null is that you can do the following nifty trick:
return EtagFix("EtagValue", HttpCacheability.Public, TimeSpan.FromHours(1)) ?? File(Server.MapPath("~/Content/mylargefile.dat");
The reason that this is cool is that "File(Server.MapPath("~/Content/mylargefile.dat")" will ONLY be called with EtagFix returns null. This avoids 'expensive' action result implementations to be created and do work that they do not have to do.
Today I got the following Subversion message via TortoiseSVN while I wanted to commit some changes.
\ is not a working copy
It took me a while to figure this out but it has to do with the fact that I subst the root of the branch to my S: drive. When I went to my user folder (c:\users\ramon\src\*) and performed a commit it just worked as expected.
The reason for the substition is that when I compile the sources that the S: drive paths are embedded into the PDB files. When another developer then attaches the debugger to any of the applications then he only needs to have the same substitution to find all source code files. Besides that, it doesn't matter on which project I work on and no matter which drive or folder the paths stay the same. This is especially usefull as I am a console and keyboard junkie.
A long time since my previous blog as nowadays I often tweet my ramblings but this one does not fit a tweet :-)
Sometimes you are working with strong named assemblies and when you are having unit tests and want to access internals then you have to use the InternalsVisibleTo assembly attribute. So to discover the public key token I ran “sn.exe –tp project.publickey” and then you get the public key (long) and the public key token (short).
Microsoft (R) .NET Framework Strong Name Utility Version 4.0.30319.1
Copyright (c) Microsoft Corporation. All rights reserved.
Public key is
0024000004800000940000000602000000240000525341310004000001000100ff6b089e3c4aaa
a96d775c3e431ea5b8b77fe2364be31793d0baf518ba39477e7fcfc027871d184e169d70ee2940
4dc26dc66c9ab970ad9a3d78be146716e10fdc4b4d3e821a7f402498ccb30f95eaca3922075354
ecdf7bb57b20a20579cba375de71e15f298f779aad7b421f4c0ee5f7c299b528f10574f64e5610
5ea3d7af
Public key token is 67178dccc283ce39
So I used the following attribute:
[assembly: InternalsVisibleTo("My.Project.Tests, PublicKeyToken=67178dccc283ce39")]
And got this nice compiler error:
Friend assembly reference is invalid. Strong-name signed assemblies must specify a public key in their InternalsVisibleTo declarations.
Then I pasted the long variant in the InternalsVisibleTo attribute and it compiled but I knew for 100% that the short version had to work. After investigation there seem two ways to pass the required strong name public key information. You can choose if you want to pass the whole public key or the public key token.
When both assemblies are signed then you need to pass the full PublicKey.
Today I got reminded again that it is sometimes required to adjust thread pool settings. This time to test some possible connection issues and I required to open a number of connections simultaneously and also use them in parallel.
The test system is a virtual machine which only has one core so the defaults that .net uses are based on that. I first thought that the problems were caused by nunit but pretty soon found out that the case had to do with the thread pool. When I queried the current values via ThreadPool.GetMinThreads it told me that the thread pool used just one thread as minimal. After forcing that with ThreadPool.SetMinThreads to a thread count in where I could test my scenario I still had issues.
I am now using a custom Parellel.For which I adjusted so that I can set a different ChunkSize (set to 1) and ThreadCount for testing purposes.
At my job (Company Webcast) we have several API’s for our customers to use. One of those API’s allow webcasts to be created and modified and that interface has data containing dates. Our platform works with UTC date time’s as we are an international operating company so it is logical for use to store those as UTC.
We use WCF and yesterday we had a very weird issue where calls failed. After investigating the issue we found out that the cause was that how the date time got supplied to our service in the message
The following values are valid in an XML message:
<ns1:ScheduledStart>2010-05-26T17:00:00+02:00</ns1:ScheduledStart>
<ns1:ScheduledStart>2010-05-26T15:00:00Z</ns1:ScheduledStart>
A WCF service accepts both values but it treats them different which I did not expect! The first value became 2010-05-26 17:00 where DateTime.Kind is set to Local and the second becomes 2010-05-26 15:00 with DateTime.Kind set to UTC. This amazed me a bit as I assumed that both would always result in either a UTC or Local DateTime.
The reason it fails is that another argument states the time-zone from where the live webcast will be held. This is used in combination with the DateTime to convert the DateTime value to a local time to inform the viewer about the conditions of the event. This code assumed that the incoming DateTime value would always be of kind UTC.
So now our front-end api’s convert incoming DateTime values to a DateTime value with kind UTC.
This could also be a problem when you persist this DateTime to for example a database and your storage logic does not convert the DateTime from/to UTC or Local depending on your needs. We use NHibernate for storage and it does not by default has a way to set UTC/Local to a <property> definition. This can really become a problem when time is part of your business logic as it is in ours as we use it to schedule tasks and it is very important to know it a time is UTC or not especially when something happens on the other side of the world.
I often hear that NHibernate is not usable for selecting records as it is not possible to perform a not equal comparison with the criteria api. I must admin that it took me a while before I found out but it really is more logical when you know. Lets take a look at the following example:
// Select entries where name = "Ramon"
var criteria = DetachedCriteria.For<MyCoolClass>()
.Add(Restrictions.Eq("Name", "Ramon"));
Your first reaction it to find the opposite of Restrictions.Eq but then you are amazed that it does not exists. The solution is so simple that it will almost embares you:
// Select entries where name != "Ramon"
var criteria = DetachedCriteria.For<MyCoolClass>()
.Add(!Restrictions.Eq("Name", "Ramon"));
Do you see the difference? I added an exclamation mark before Restrictions.Eq to invert the restrictions operator.
So now you know and probably never forget ;-)
I just read a very cool NHibernate trick to let your application start faster that was mentioned by Ricardo Peres:
Configuration cfg = new Configuration().Configure();
IFormatter serializer = new BinaryFormatter();
using (Stream stream = File.OpenWrite("Configuration.serialized"))
{
serializer.Serialize(stream, cfg);
}
...
using (Stream stream = File.OpenRead("Configuration.serialized"))
{
cfg = serializer.Deserialize(stream) as Configuration;
}
Yet again a VST did not load in my Ableton Live DAW. This time it is the Amplitube 2 VST by IK Multimedia. It did work if I launched Ableton with administrator priviledge but we al know that we shouldn't do that if it is not necessary and running as administrator to load a VST sure is not very useful. I launched the excellent process monitor and filtered for stuff coming from the ableton process that did not succeed and I found out that Amplitube 2 is writing to the file:
C:\Windows\msocreg32.dat
A very naste way from IK Multimedia to put that file in the Windows folder as normal users cannot create or modify that file. The file is created by Amplitube so it must be some sort of timer file for the product evaluation.
To fix this without running as administrator and with UAC enabled do the following:
- Launch your DAW by right clicking its icon and select "Run as administrator".
- Rescan your VST folder for new plugins. Amplitube gets loaded and the above mentioned file is created. You should be able to use the VST.
- Quit your DAW.
- Go to c:\Windows with file explorer.
- Find the file "msocreg32.dat", right click it and select properties from the context menu.
- Go to the security tab
- Click "Edit". A UAC box will appear to ask you for permission and allow it.
- Select the "Users" group.
- Set a checkmark next to "Modify" in the lower list.
- Click twice on "OK" to close both dialogs.
- Launch your DAW as you normally would.
Now you are running as a normal user with a function Amplitube VST. This happens to more VST's like for example the Native Instruments collection required quite a lot of folders to be writable by the user. Because the files are located in the Program Files folder this is not allowed. Just do the above mentioned modification on *only* the "c:\Program Files (x86)\Native Instruments" folder and no more popups to select another folder to write to.
The tool called "process monitor" by Sysinternals really helps to identify such permission problems so download it if you have similar problems with other VST's in your favorite DAW.
I was having a problem where NHibernate did not automatically delete childs if a collection was emptied by calling IList.Clear() like in the following code example:
var s = GetSession();
var parent = s.Get<Parent>(1);
parent.Childs.Clear();
What did work ofcourse was code like the following before executing clear which marked the records for deletion and NHibernate executed the correct delete statements when the session was closed or flushed.
foreach(var c in parent.Childs) s.Delete(c);
I searched the internet for quite a while and playing around with the cascade and inverse attributes in the .hbm files as I knew it had be an error in the configuration.
<bag name="Topics" cascade="all" inverse="true">
<key column="Webcast_Id"/>
<one-to-many class="AddonIndex"/>
</bag>
After searching for quite some time I found that the problem was cascade="all" which should have been cascade="all-delete-orphan" and when I read that on a forum I had a very bigy WTF moment. I *really* assumed that all would do the deletion of the orphans as that is what the keyword implies, that it does *all* while in reality it does all except deletion of orphans.
So I would like to suggest the (N)Hibernate team to change the names of the cascade values or just ditch the all value.
My midi hardware it working nice in my DAW home studio but today I noticed that I do not have the ability to change the default midi out device in Windows 7. After googling around it seems that this was also the case in Windows Vista. But luckily there are options to configure the default out device!
The first that I found was the Windows Vista MIDI Mapper control panel and minutes later the Vista MIDI fix. The control panel application fixed my problem but only lists hardware midi stuff like my MIDI USB keyboards and the hardware midi output of my Creative card as the Vista MIDI fix application lists more midi out options but I haven' not tested those yet.
Both applications run without any problems here on my Windows 7 RC x64 installation.
I tried to install the virtualbox machine additions in my OpenSUSE guest but had some problems. Mouse integration worked but display resizing did not. It turned out that I just didn’t read the output from the additions package well.
Remove all "Modes" lines from the "Screen" section and any Option "PreferredMode" lines from "Monitor" sections.
Did that by removing the Option from the Monitor section and all Modes lines from the subsections of the Screen section and it now working as it should with display resizing. The only thing that does not work is clipboard sharing.
I just saw a cool trick done in a finalizer of a class. When a class implements IDisposable then its creator needs to call Dispose when it is finishen. Lots of developers forget this and that usually results in system resources that are locked until the garbage collector thinks its time to do its work.
The code construction I saw was:
~MyCoolClass()
{
System.Diagnostics.Debug.Assert(false);
Dispose(false);
}
I have never thought of doing this but it makes sense to just add a assert to a finalizer to get notified that you didn’t dispose the object. The finalizer will never be called if it would because of the GC.SuppressFinalize(this); statement that should be done when calling IDisposable.Dispose on the object.
It could be that you are getting this in a service and then this doesn’t make any sense but then you could just log an error instead.
I have bought the Samson C03U USB microphone and after plugging it into an available USB port it worked immediately. I then wanted to use it from any of my sequencers (Cubase AI and FLStudio) but only to find out that neither can use multiple ASIO devices simultaneously. Not that difficult to understand as probably only one ASIO device can be active at a time and for that you get low latency audio out/in in return. I also saw an ASIO DirectX Full Duplex driver. Probably a ASIO host that delegates to direct sound. Had not seen that before so I selected it and there I could select the audio devices that I wanted to make available and it worked! I could use my Creative X-FI Extreme Gamer for audio out and my Samson C03U for audio in. The only big problem is that I had lots of latency. After tweaking it I found out that I could lower the buffersize to 512 samples instead of the default 2048 which decreased the latency but it is still not very enjoyable to listen live to the incoming audio.
I remembered that I had used ASIO4ALL a long time ago when I didn’t had ASIO drivers for my onboard sound. ASIO4ALL is similar to the Directsound ASIO provider in configuration but in ASIO4ALL I could lower the buffer sizes to 64 samples which reduced the latency to acceptable levels to listen to the incoming audio. A few clicks occur in the out so I increased that to 96 samples.
I think that I have lower latency using the ASIO4ALL drivers instead of the drivers from Creative.
We were having some mail problems. This is not always the case but we now found the culprit. The problem was that our domain record *had* a CNAME record referring to the A record of the webserver. Some mail servers will use the CNAME record instead of the MX record when the smtp server needs to be resolved.
mywebserver.mydomain.com A 127.0.0.1
mydomain.com CNAME mywebserver.mydomain.com
www.mydomain.com CNAME mywebserver.mydomain.com
This will result in lots of mail servers not being able to deliver the mail. So today’s (DNS) lessons learned are:
- Do not set a CNAME record on your domain
- Do not use a CNAME record for a catch all (*.mydomain.com) as this too suffers from the same problems.
You can still use CNAME records for your ‘service’ subdomains that refer to actual hosts (A and AAAA records). This is still the most efficient way to handle your ip addresses for your actual machines especially when you also support ipv6.
The most frustrating thing here is that the behavior differs on platforms and applications so it took a while before this was discovered.
I was just chatting with a collegue about my hardware history and thought it was time for an update. My hardware list is as follows:
- MSX2 HB-F9P
- Amiga 500 1MB + Action Replay III
- Amiga CDTV 1MB + DIP switch KS1.3
- 486DX33 8MB + SB16 + GUS
- 486DX266 32MB + SB16 + GUS
- Pentium 200MHz MMX @ 225MHz 128MB + GUS IW + PowerVR + Voodoo2
- Pentium 4 1GHz 512MB
- Pentium D 3,4GHz 2GB + ATI HD2600XT + NVidia 9800GT
The first computer that I saw as a kid was an Atari 2600 which friends of mine had and that was pretty amazing. A few years later I got my own computer, the MSX2. Later the father of the friends that had the Atari 2600 bought an Amiga 2000 and I really was flabbergasted when I saw it in action. I was already in love with the MSX2 but it extended to the Amiga and soon I was an owner of an Amiga 500! I somewhere sold my Amiga hardware which I needed to do to buy a PC but now I regret that dicision :-).
The MSX died somewhere around the year 2000 when heavy rain filled the basement where it was stored but a friend wanted to get rid of his MSX2 hardware. Two Philips NMS 8280 but only one keyboard. I still have these devices and sometimes boot them up with either one of the few cartridges that survived the basement pool experiment.
Somewhere a long I also owned a NES but I was and probably never will be a console person.
I learned programming on the MSX in BASIC and a little bit hacking with disassemblers. On the Amiga I started with AMOS, REXX and later on SAS C and 68000 assembly. I then made the transition to the PC where I was first programming in Turbo Pascal combined with x86 assembler and later on Watcom C/C++. I then started programming for a living and programmed MSVC/VB6 in Visual Studio 6 in Windows with COM(+) and later on in .net 1.0.
I was always interested in other development platforms and operating systems. I experimented a lot with all kinds of languages and Linux distributions, OS/2 and BeOS but nowadays I primarily program in c# because I am a professional .net developer for a living but I still experiment in my free time although I’m not such a geek anymore as I was 10 years ago.
More Posts
Next page »