I finished reading it for a second time through yesterday.
Sunday, August 31, 2014
Friday, August 29, 2014
We had a lunch and learn at work yesterday on patents, copyrights, trademarks, and trade secrets.
A distinction was made between:
- patents, which are inventions
- a request for a patent to the US Patent and Trademark Office (USPTO) must be filled within one year of a submission to the public
- software wasn't considered patentable until the 1990s, but... now it is
- "Patented" or "Patent Pending" are the legalese callouts that decorate applicable copy surrounding this intellectual property
- patents may be of:
- processes
- machines
- composition of matter
- articles of manufacture
- copyrights, which are works of authorship
- © denotes a copyright in paperwork officialesqueness
- trademarks, which are brands or product names
- legalese callouts that decorate applicable copy surrounding this intellectual property:
- ® is for registered trademarks
- ™ is for trademarks which may one day be officially registered (me remembers from a college class on trademark law that one may trademark applicable brands or product names "on their own" without any form of paperwork filing or red tape process navigation and what is more an assumed trademark exists for creations in this flavor of IP and if a violation of the trademark occurs significant ammunition to argue a case for trademark violation lays in the hands of the abused party)
- ℠ is for service marks which are for downloadable software
- legalese callouts that decorate applicable copy surrounding this intellectual property:
- trade secrets, of which an example might be the recipe for making Coca-Cola
Serialize a C# object to a string of XML.
This offers something like:
string xml = null;
using (var memoryStream = new MemoryStream())
{
using (var xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8))
{
var xmlSerializer = new XmlSerializer(whatever.GetType());
xmlSerializer.Serialize(xmlTextWriter, whatever);
using (var xmlTextWriterMemoryStream = (MemoryStream)
xmlTextWriter.BaseStream)
{
UTF8Encoding utf8Encoding = new UTF8Encoding();
xml = utf8Encoding.GetString(xmlTextWriterMemoryStream
.ToArray()).Substring(1);
}
}
}
This suggests a way to get the string back to a C# type might look something like this:
Whatever whatever;
using (var stringReader = new StringReader(xml))
{
var xmlSerializer = new XmlSerializer(typeof(Whatever));
whatever = (Whatever) xmlSerializer.Deserialize(stringReader);
}
If you serialize a type to XML in C#, put it in a string, and then, while stopped at a breakpoint in Visual Studio, copy and paste the text out of the string, remember to take out the backslashes before you do anything substantive with it. Otherwise the backslashes will cause C# to blow up when you attempt to deserialize.
Get PUT methods to stop throwing "404 (Not found)" at the ASP.NET MVC Web API.
Per this, this needs to go into Web.config in the system.webserver section:
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/>
</modules>
Thursday, August 28, 2014
trim in js
.trim() in JavaScript does just what you'd think...
var urlVariables = window.location.href.split("/");
if (urlVariables[urlVariables.length-1].trim() == "") {
Addendum 2/3/2018: .trimRight() and .trimLeft() are also a thing. There is a way to do left padding to right align things too. I'm not sure how "pad left" and "trim end" or "trim start" all work.
Venn Diagrams
...are the diagrams which show a piece of a dataset (circle) partially overlaying a different dataset (circle) where common data exists in the two different datasets.
Wednesday, August 27, 2014
StructureMap.MVC5
...is a NuGet package which allows one to bring in dependencies at an ASP.NET MVC controller implicitly when the constructor is called like so:
namespace Whatever
{
public class MyController : Controller
{
public IMyRepository MyRepository { get; set; }
public IFrameController(IMyRepository myRepository)
{
MyRepository = myRepository;
}
public ActionResult Index()
{
var model = MyRepository.GetThatOneThingWeNeed();
return View(model);
}
}
}
In this example, when one tries to visit http://www.example.com/my/ at a browser, the appropriate class which implements the IMyRepository interface is magically hydrated at the controller's constructor. The NuGet package creates a "DependencyResolution" folder at an MVC project to facilitate the code to empower this trick. The code in the classes at the App_Start folder are dressed up some to appropriately utilize what is in the DependencyResolution folder too. DefaultRegistry.cs in DependencyResolution seems to be the new place to wire up the dependencies one used to wire up in the Global.asax.cs in yesteryear (MVC3). StructureMap.WebApi2 is the sister NuGet package for the Web API. WebActivatorEx is used to pull some of the new code that comes with the other two packages out into attributes in lieu of having it liter Global.asax.cs.
IHtmlString!
Make one like so:
public ActionResult Whatever()
{
IHtmlString html = new HtmlString("<strong>I'm yelling!</strong>");
return View(html);
}
Use what you just made like this:
@model IHtmlString
@{
Layout = null;
}
<html>
<head>
<title>Whatever</title>
</head>
<body>
@Html.Raw(Model)
</body>
</html>
Availability Groups in MSSQL 2014
...are replacing mirroring. The groups have replicas instead of mirrors and one may query replicas and not just the master.
throwing ASP.NET MVC Web API errors while also playing nicely with CORS
In an ASP.NET MVC Web API method one may typically throw an exception like so:
throw new Exception("No data was provided.");
...and then catch it at a jQuery .ajax implementation like so:
$.ajax({
type: "POST",
url: 'http://www.example.com/api/whatever',
dataType: 'json',
data: whatever,
success: function (result) {
alert("success: " + result);
},
error: function (request, status, error) {
var responseText = JSON.parse(request.responseText);
alert(responseText.ExceptionMessage);
}
});
HOWEVER, if you are doing cross-site interactions and CORS is thrown into the mix, you cannot throw an error in this way and expect the specific error to make its way back to the jQuery implementation. Instead, try doing something like so in a method that returns an HttpResponseMessage anyways in the event of everything going well:
var error = Request.CreateResponse<string>(HttpStatusCode.BadRequest,
"No data was provided.");
error.Headers.Add("Access-Control-Allow-Origin", "*");
return error;
The catching looks a bit different too:
$.ajax({
type: "POST",
url: 'http://www.example.com/api/whatever',
dataType: 'json',
data: whatever,
success: function (result) {
alert("success: " + result);
},
error: function (request, status, error) {
alert(request.responseJSON);
}
});
Sometimes Google Chrome will be zoomed to 100% yet appear and behave as if it is zoomed to 125% in Windows 8!
To fix:
- right-click in the desktop and then pick "Personalize"
- at the lower left of the window which appears click "Display"
- you will now be at a window which has "Change the size of all items" at the top and herein you should click "Custom sizing options"
- the "Custom sizing options" dialog box appears where you should change the dropdown to "100%" and then click "OK"
- click "Apply" back at the window which says "Change the size of all items" at the top
Tuesday, August 26, 2014
Make NuGet get your missing dependencies in Visual Studio 2013.
- Enable NuGet in building at: PROJECT > Enable NuGet Package Restore
- NuGet "exited with code 1." ...is an error message I saw even after building with NuGet enabled, basically because some of the older dependencies could not be found
- go to: TOOLS > Library Package Manager > Package Manager Console ...at this point as it is time to hope the newer versions of what is missing will work
- "Install-Package Whatever" is the syntax at the console for installing something
- I needed Microsoft.Practices.ServiceLocation so I ran "Install-Package CommonServiceLocator" and at first it complained because I also did not yet have StructureMap... and yet NuGet ultimately found the missing dependencies and worked out its mess
- "Install-Package Whatever" is the syntax at the console for installing something
- go to: TOOLS > Library Package Manager > Package Manager Console ...at this point as it is time to hope the newer versions of what is missing will work
- NuGet "exited with code 1." ...is an error message I saw even after building with NuGet enabled, basically because some of the older dependencies could not be found
This configuration section cannot be used at this path. This happens when the section is locked at a parent level. Locking is either by default (overrideModeDefault="Deny"), or set explicitly by a location tag with overrideMode="Deny" or the legacy allowOverride="false".
This error suggests that something has not yet been prepped in IIS. Type "turn windows features on or off" at the search at the charm bar in Windows Server 2012 R2 Datacenter to get the "Add Roles and Features Wizard" anew, then... well, you know...
issue number
Not all Maestro cards have start dates (or issue dates) on them as it turns out, and another field which one should try to collect when payment processing a Maestro card which may or may not be on an individual card is an issue number. As a concept, an issue number identifies a particular card for an account. In an American Express account, two cards, perhaps for a husband and wife, may both have the same credit card number, but may be distinguished in terms of which card was actually used to make a payment by the CVV number. The issue number in the Maestro scenario facilitates differentiation comparably. This concept may have existed in Switch and Solo cards too, but these card types are now absorbed into Maestro.
StructureMap.ObjectFactory is obsolete
This suggests the "modern" way to make a singleton which brings back an injected dependency in a StructureMap implementation might be like so:
public static BreadcrumbTracker ObtainTracker()
{
return StructureMap.ObjectFactory.Container.GetInstance<BreadcrumbTracker>();
}
Monday, August 25, 2014
3DS is optional.
A vendor offering a way to pay by credit card does not have to provide a way for cards with 3-D Secure security to go through 3-D Secure sanity checking. This form of security may be enabled if a vendor wishes if or it may not be. Think of how SPF records help in DNS and yet how they too are really just optional.
Show the "My Computer" icon on the desktop in Windows Server 2012 R2 Datacenter.
- click the "Server Manager" tile at the Windows menu
- click "Dashboard" at upper left of the "Server Manager" window you'll see
- then click on "Add roles and features" in the central content
- you will next start walking through the "Add Roles and Features Wizard"
- just stick with the defaults until you get to "Features" ...for example: it is good to just leave the radio buttons for "Role-based or feature-based installation" and "Select a server from the server pool" checked
- at "Features" this suggests that the checkbox for "Desktop Experience" which is nested beneath "User Interfaces and Infrastructure" should be checked
- afterwards you will need to restart Windows Server 2012 R2 Datacenter
- after the restart, you should be able to click in the desktop and pick "Personalize"
- at the "Personalization" window click "Change desktop icons"
- check the checkbox for "Computer"
- the icon will appear, though it will be labeled "This PC" instead of "My Computer"
WQL is SQL for WMI
WQL stand for WMI Query Language and WMI stands for Windows Management Instrumentation. Some links:
Sunday, August 24, 2014
different joins in MSSQL
Here are how the four types of joins will behave against these two database tables. First off, I got a surprise when it turned out the ambiguous join wherein only the world join is specified like so...
SELECT *
FROM LowercaseLetters AS l
JOIN UppercaseLetters AS u
ON l.LowerId = u.UpperId
...behaved not like a left join as I expected here, but like an inner join. It did the same thing as this:
SELECT *
FROM LowercaseLetters AS l
INNER JOIN UppercaseLetters AS u
ON l.LowerId = u.UpperId
The left join looks like so in contrast:
SELECT *
FROM LowercaseLetters AS l
LEFT JOIN UppercaseLetters AS u
ON l.LowerId = u.UpperId
The super magic amazing right join looks like this:
SELECT *
FROM LowercaseLetters AS l
RIGHT JOIN UppercaseLetters AS u
ON l.LowerId = u.UpperId
The cross join returns 169 rows!
SELECT *
FROM LowercaseLetters AS l
CROSS JOIN UppercaseLetters AS u
Saturday, August 23, 2014
Make your own Windows Service in Visual Studio 2013 in nine easy steps.
One. Make a new project in Visual Studio 2013. Under the Windows templates within the Visual C# templates there is now a "Windows Service" template. You will want to use this. I name my application JaeschkeService in this example. In Visual Studio 2010 implementations I get the impression that one just made a console application and then made the one class inherit from ServiceBase, bringing in a reference to System.ServiceProcess. Don't do this. I tried to set something up in this manner and whenever I went to start the service I'd get an opaque error message which read:
Error 1053: The service did not respond to the start or control request in a timely fashion.
Two. Make code changes. There are really only two files of interest in the new application. One is the typical Program.cs that exists in any console application. It basically looks like this:
using System.ServiceProcess;
namespace JaeschkeService
{
static class Program
{
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
}
}
The other is our service. It is called Service1.cs and it basically looks like this:
using System.ServiceProcess;
namespace JaeschkeService
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
}
You may have noticed that Service1.cs does a lot of nothing. Let's fix that. Using suggestions here, I have doctored up Service1.cs to once per minute write the current time to a text file at C:\Whatever\stuff.txt like so:
using System;
using System.IO;
using System.ServiceProcess;
using System.Text;
using System.Timers;
namespace JaeschkeService
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Timer timer = new Timer();
timer.Interval = 60000;
timer.Elapsed += OnTimer;
timer.Start();
}
protected override void OnStop()
{
}
public void OnTimer(object sender, ElapsedEventArgs args)
{
string file = @"C:\Whatever\stuff.txt";
using (Stream stream = new FileStream(file, FileMode.Append))
{
byte[] bytes = ASCIIEncoding.ASCII.GetBytes(DateTime.Now + " ... ");
stream.Write(bytes, 0, bytes.Length);
}
}
}
}
Three. You will need to switch to viewing Service1.cs in the designer mode to make the next few changes, so let's make the switch now. To be honest, you will most likely have started out seeing Service1.cs in designer mode and would have had to manually switch to the code view in the previous step to make the code changes. I guess I should have said something before now. Anyways, you may switch views by right-clicking upon Service1.cs in the Solution Explorer and then picking either "View Designer" or "View Code" from the menu which appears.
Four. If you just click in the designer pane for Service1.cs you will see properties for the service in the "Properties" pane. The default name is just "Service1" and I think we should change this. I change it, the "ServiceName" setting, to "MyService" in this example.
Five. We need an installer. Right-click in the designer pane for Service1.cs and pick "Add Installer" to make this happen.
Six. You will now see a new file for the installer in the Solution Explorer. Build the application at this point. Once you build the application you will be done working in Visual Studio 2013. We are well over halfway through the steps at this point. w00t!
Seven. Next let's install the service by opening the "Developer Command Prompt for VS2103" as administrator, navigating to the Debug folder inside of the bin folder within the project we made, and then running this command:
installutil.exe JaeschkeService.exe
By the way, if you ever want to uninstall a service, you also navigate to the same place and then run a command like this:
installutil.exe /u JaeschkeService.exe
Eight. You will need to enter credentials for an account to run the service in the "Set Service Login" dialog box which appears. The account you use should be an account that has permissions to do the things you need done. For example, I used an account that had permissions to access and edit C:\Whatever\stuff.txt of course.
Nine. Open the "Services (Local)" list. In Windows 8, I found it by typing "services.msc" at the "Search" at the charm bar. Right-click on the service you just made and pick "Start" to get it running. Double-clicking on the service will expose even more options and at the "General" tab one may set the "Startup type:" to "Automatic" to make the service start automatically when the PC itself starts up. My service was found under the list with the name "MyService" where I started it and let it run a bit. I checked C:\Whatever\stuff.txt and as expected I could see the precious minutes left in the last day I have before I turn forty just ticking away like so:
8/23/2014 10:14:05 PM ... 8/23/2014 10:15:05 PM ... 8/23/2014 10:16:05 PM ...
Friday, August 22, 2014
I learned Wednesday that IDisposable is one of the big differences between .NET Framework 1.0 and .NET Framework 1.1.
That means that as painful as 1.1 was, there was once something even worse!
Drag the "playback head" backwards when debugging in Visual Studio 2013.
When stopped at a breakpoint or a line you walked to by way of F10 or F11 from a breakpoint, right-click at the line you wish to back up to and pick "Set Next Statement" from the line items which appear. You may also click where you wish to be and then press Ctrl-Shift-F10!
A better way to install the AttachTo plug in in Visual Studio 2013.
- at the TOOLS menu go to "Extensions and Updates..."
- click "Online" at the left of the "Extensions and Updates" pane which appears
- search for "AttachTo" at the upper right
- find the appropriate line item and click its "Download" button
I tried just downloading the .vsix online and trying to double-click it to install it but it misbehaved. :( This is the other way to approach the same challenge.
You are using an unlicensed and unsupported version of DotNetNuke Professional Edition. Please contact sales@dnncorp.com for information on how to obtain a valid license.
To make this DotNetNuke error go away:
- log in as "host"
- click the "Host" link at the upper right
- click on "Activate your License" under the "Professional Features" subsection of the page you see
- register here
Note: For this to work, you will need the "DNNCorp" folder in the "DesktopModules" folder within the DotNetNuke application. I hate to say this explicitly as you probably should just already have this folder, but in my circumstance, I did not. I seem to be cobbling together a working DotNetNuke app. Anyways, in the absence of this folder the "Activate your License" link more or less goes nowhere.
Allow other environments to ping into Windows Server 2008 R2.
- type "control panel" at the start menu
- at the control panel click on "System and Security" and then "Windows Firewall" and finally "Advanced settings"
- click on "Inbound Rules" at the upper left of the "Windows Firewall with Advanced Security" dialog box
- at least one of the line items here with a name which starts out with "File and Printer Sharing" needs to be enabled
- you may enable a rule by right-clicking upon it and picking "Enable Rule"
- in my case I sorted all of the rules by name and then enabled the first two "File and Printer Sharing" rules which were named "File and Printer Sharing (Echo Request - ICMPv4-In)" and "File and Printer Sharing (Echo Request - ICMPv6-In)"
Thursday, August 21, 2014
Open PowerShell at Windows 7 by just typing "powershell" at the start menu.
This command will give you information on your memory banks:
Get-WmiObject CIM_PhysicalMemory | select banklabel,capacity,caption,devicelocator,partnumber
One hundred percent of text messages are read and for every four emails you send to friends asking for a donation you will get one donation!
These interesting metrics were suggested by a Joel Rice at an event I went to last night which was a warm up for the 2014 Austin Heart Walk to be held on October 18. The event was at "Maggiano's Little Italy" in the Domain.
Allow other environments at your LAN to access web sites your VMware VM hosts.
at the "Network Adapter" setting check the checkbox for: "Bridged: Connected directly to the physical network"
Tuesday, August 19, 2014
ASP.NET State Service
In the name of fixing this ASP.NET error...
Unable to make the session state request to the session state server. Please ensure that the ASP.NET State service is started and that the client and server ports are the same. If the server is on a remote machine, please ensure that it accepts remote requests by checking the value of HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters\AllowRemoteConnection. If the server is on the local machine, and if the before mentioned registry value does not exist or is set to 0, then the state server connection string must use either 'localhost' or '127.0.0.1' as the server name.
...this suggests you need to start the "ASP.NET State Service" Windows Service.
- In Windows Server 2008 R2 type "Administrative Tools" at the start menu.
- Pick "Services" in the list that appears in a Window to bring up the list of Windows Services.
- Find "ASP.NET State Service" which will have a "Status" of "Disabled" unfortunately.
- Double-click the line item to edit it and then set the "Startup Type" to "Manual" to allow for starting the service.
- Click the "OK" button to get back to the list of services.
- Right-click on the line item for "ASP.NET State Service" and pick "Start" to start the service.
Turn on IIS at Windows Server 2008 R2.
This has a pretty good cheat sheet.
- Right-click on the "Computer" icon at the desktop and pick "Manage" from the menu that appears.
- At the "Server Manager" pane which appears click on "Roles" at the left and then "Add Roles" at the right.
- The "Add Roles Wizard" appears. Here, click on "Server Roles" at the left and then the "Web Server (IIS)" checkbox.
- Click the "Next" button and walk through the wizard!
Join a domain at Windows Server 2008 R2.
Follow the first three steps here and then click the "More..." button.
Multiple snapshots in VMware brings with it a performance hit.
I am learning today that this is not something to do willy-nilly.
A friend told me of Oracle VM VirtualBox last night.
VirtualBox is another way to do Virtual Machines not unlike VMware. I think we may have been using this @hand. I sounds familiar.
Sunday, August 17, 2014
UserGroup.tv
...seems pretty awesome. There are a lot of recordings of tech talks you may have missed there. I've been to two different talks now (one in Fort Worth and one in Austin) where Shawn Weisfeld was taping the talk for UserGroup.tv. Cool!
End of Xbox?
As of the coming of new CEO Satya Nadella, Microsoft has shut down its Xbox wing and let go of thousands of Xbox related employees. This article suggests that perhaps Microsoft will just sell off Xbox to another company so maybe the Xbox isn't done, done, done. The Xbox and also Bing were the biggest money holes for Microsoft at the beginning of this year. I can remember going to a talk in the 1990s wherein a speaker said that if you put Sony and... I dunno, maybe Nintendo, together that you'd have a company as big as Microsoft in terms of revenue. Microsoft seems to charge into technologies where it feels another entity might challenge it (threaten it) and thus I guess they thought they needed to get into gaming. It does seem that they are more legitimately threatened anymore by Google which has grown quite impressive, though I cannot imagine Bing rivaling google.com. Meh. I digress.
I'm hearing of Windows Workflow Foundation for the first time today.
This has some notes on it. The Wikipedia write up says it is to: "implement long-running processes as workflows"
Saturday, August 16, 2014
Friday, August 15, 2014
There is still no Adobe Flash at the iPhone.
Six years later... this fact has really changed the web, huh? Flash is gone, and I don't miss it.
Get the contents of an Adobe Illustrator file into XAML.
This isn't too tough in our modern time. In Visual Studio 2013, right click on a .xaml file and pick "Open in Blend..." which will spin up the Blend app where you should next just pick: File > Import > Import Adobe Illustrator File... (just save the file when you're done importing/that's it)
What version of DotNetNuke am I using?
This tells us that running... Select * from Assemblies ...at the DotNetNuke database will reveal what version of DotNetNuke is running and that sure seems to be true! Word.
Spotify
I went to lunch with two coworkers today. I drove my car to the restaurant. As I drove the CD I bought recently played. One of my coworkers asked what was playing and when I showed him the case he wondered aloud if he could get the songs on Spotify. He uses Spotify to manage his music instead of buying CDs (as I do) because he is... smart/modern. I Googled Spotify today and it looks like it is a music service for a smartphone or a tablet like iTunes, but also platform agnostic and, per this, less expensive all and all. The CD in my story is "Pitch Black Prism" by "Alias" which is brand new as of this month and contains a lot of cool instrumental tracks. The restaurant in my story is "WinFlo" which is also pretty new (newer than this three-year-old blog) and has Italian food and pizzas. (It is in Austin, Texas.)
Thursday, August 14, 2014
Concatenate PDFs the right way.
You may perhaps hack PDF concatenation like so if you don't have Adobe Acrobat, but if you actually have the software, you may definitely slurp the contents of one PDF into another by going to "Insert from File" under "Pages" under "Tools" as seen here:
http://www.xiconeditor.com/ seems like a perfectly good tool for editing .ico files!
Let's make some icons! Yay!
Addendum 8/22/2014: My boss pointed out to me today that http://icofx.ro/ might be a better tool to use. (Just get a free trial.) The reason is that the first tool doesn't do transparencies as good and transparent pixels may appear as black instead of transparent in some cases when they are done wrong. While I am talking about icons, it is possible to make an icon in a tool like Photoshop too by making a .bmp and then manually changing the extension to be .ico, but you don't want to do this. Icon files have four sizes:
- 64 x 64 pixels
- 32 x 32 pixels
- 24 x 24 pixels
- 16 x 16 pixels
...and, if you do the .bmp to .ico trick you are just accomodating one of the four sizes and the image will just scale poorly to fit the other three sizes when circumstance demands.
Addendum 10/6/2014: This is wrong. I think there are eight sizes.
Wednesday, August 13, 2014
You cannot store a CVV number at a database.
...not without being guilty of breaking with PCI standards. You may store a credit card number if the credit card number is tokenized. You may also dance in the grey areas a little bit by storing an encoded* CVV temporarily at a database and then wiping it out when a transaction is completed. In this scenario you'll also have to have a process running that cleans away CVVs from abandoned transactions. If you are wondering how a wallet works without storing CVVs it is merely by not storing CVVs at all. You do not have to use a CVV in a transaction, but parties which take payments which do not require CVVs are apt to pay higher interchange rates and stick their necks out for more liability in general should a claim be disputed.
*or perhaps encrypted. Does it matter? If the number is encrypted one may quickly encrypt the numbers between 001 and 999 to find the match. How much does encrypting versus encoding matter in this scenario. I'm not sure of the standard here.
Here is something to get mad about. Handles no longer snap to grid intersections in Adobe Illustrator.
- Download the Adobe Illustrator CC 2014 release, the most current version of Adobe Illustrator as of this writing.
- Under the "View" menu pick "Snap to Grid." I think the grid itself will be visible by default when you spin up Illustrator for the first time but if it isn't you may pick "Show Grid" from the "View" menu to see it.
- Draw some lines that have vertices that line up at the grid's line intersections.
- Get the "Anchor Point Tool." This is the tool that looks like a letter V which has been rotated 145 degrees clockwise to sort of point both upwards and leftwards. It may be found under the set of tools which at first startup has the "Pen Tool" showing which is the set of tools five positions down from the top in the default "Tools" panel. Alternatively, you may just press Shift-C to switch to the "Anchor Point Tool."
- Click on a vertex and drag outwards. The vertex will expand two handles. Try to make the immediate handle snap to a grid intersection. You cannot. You could do so in previous versions of Illustrator, but now this ability is lost.
- Let go and try to drag just one of the handles by its endpoint to a grid intersection by itself. You won't be able to snap to the grid this way either.
This tells the old lie: "It's not a bug, it's a feature." ...like so: "For the 2014 release, the anchor handles are disengaged from snapping to a grid or a point, so you can have fine control while editing your paths." And yet this, raises the suspicion that the new freedom is really just a defect. I hope the suspicion is the reality. I hope there is another version of Adobe Illustrator coming to us that reverts back to the old way of doing things or at least allows us to toggle the old snapping back on. I have read online some arguments to the contrary of my disgust here which suggest that it is just peachy to have the freedom to drag handles without the angst of having them snap to grid intersections or the overhead of toggling "Snap to Grid" on and off while working, but I am not swayed. Imagine making a circle with four vertices at the topmost point, the rightmost point, the bottommost point, and the leftmost point. Imagine you wish to deform the circle at the leftmost point with the "Anchor Point Tool" and then turn around and deform the circle at the other side, the rightmost point, in a perfectly symmetrical way. You can't. While I'm on a rant, I am not in love with the image of a lion with a vagina in the middle of his forehead that I see when spin up the latest Adobe Illustrator.
Tuesday, August 12, 2014
Make lines into arrows in Adobe Illustrator.
- Open the "Stroke" pane from the "Window" menu.
- Click on the icon for showing all options to expand the pane. It is the icon immediately below the X for closing the pane at the upper right. You'll get a "Show Options" tooltip when you put your mouse over the icon.
- Set the "Arrowheads" setting.
Monday, August 11, 2014
3-D Secure
The concept of 3-D Secure has at least these four implementations:
organization | their version of 3-D Secure |
American Express | American Express SafeKey |
Visa | Verified By Visa |
MasterCard | MasterCard SecureCode |
JCB (Japan Credit Bureau) International | J/Secure (for Discover card???) |
As a concept, what this entails is a circumstance in which when you buy something online you are routed to your bank where you have to enter a password at your bank to affirm that you really want to allow the purchase to be. This adds one more security hurdle to prevent another party from abusing your credit card online.
to see the HTML behind an email in Outlook
- click in the email
- press Alt-H
- press Alt-A
- press Alt-V
- press Enter to click the “OK” button at the alert which appears
This will bring the HTML in IE where: View > Source ...will show the source code within Internet Explorer.
Sunday, August 10, 2014
ordering records in queries within an ORM implementation?
Why do I care? Why can't I just do that on the C# side? Aren't this...
public List<Person> GetPersons()
{
using (var db = new PersonContext())
{
var people = from person in db.People orderby person.Email select person;
return people.ToList();
}
}
...and this...
public List<Person> GetPersons()
{
List<Person> results;
using (var db = new PersonContext())
{
var people = from person in db.People select person;
results = people.ToList();
}
return results.OrderBy(p => p.Email).ToList();
}
...basically equal?
Friday, August 8, 2014
how to create a footer with CSS!
This HTML, styled as it is, is going to create a consistent footer within the page.
<!DOCTYPE html>
<html style="height: 100%;">
<body style="margin: 0; padding:0; height: 100%;">
<div style="min-height: 100%; background-color: #EEEEEE;">
Do<br />
Re<br />
Mi<br />
Fa<br />
Sol<br />
La<br />
Ti
<div style="padding-bottom: 20px;">
brings us back to...
</div>
</div>
<div style="margin-top: -20px; height: 20px; background-color: #CCCCCC;">
Do
</div>
</body>
</hmtl>
It is important that:
- the html and body tags get a height of 100%
- there are only two divs holding all of the content inside the body tag and the first div has a "min-height" setting of 100%
- the second div is the footer and it should be shoved down past the 100% point on the page consistently causing a scrollbar to display unless one gets rid of the scrollbar by making the top margin on the second div the reciprocal of the div's height (duh, this is heavily recommended)
- the top margin trick will force the second div to overlap the first div's bottom
- compensate for this by making the last bit of content in the first div have an amount of bottom padding equal to the height of the second div
Whew! That is a lot of rules which have to dance together for this to work. If you can get it all to work the result looks like this:
In contrast to the JavaScript stuff I cooked up here, this approach will conditionally show or not show a scrollbar at the browser itself as the situation demands and requires no JavaScript to be made to work.
This week I heard of custom data types in SQL.
These will behave just like temp tables. You may comparably carry things around in them. If you have a temp table of the same shape sprinkled across numerous stored procedures, perhaps you would have less overhead in using a custom data type. The challenge with these is that there is no way to run an ALTER command on them. If you want to change their shapes you have to drop all the stored procedures which use them, then drop them (the custom data types), and finally then recreate them.
Luhn check
...in the credit card space is a check to see if a credit card number entered may possibly be legitimate for a given credit card type.
Addendum 8/21/2014: A Luhn check is not card type validation. That is a bigger thing. A Luhn check just checks to see if a credit card number could be legitimate for any one of the card types.
Have you ever made the decision between "Use ReSharper command" and "Use Visual Studio commands" and find that you wish you could make the decision again?
Well... good news... you may! Pick "Options..." from the "RESHARPER" menu in Visual Studio 2013. Then select the node for "Keyboard & Menus" below "Environment" where you will click the "Apply Scheme" button while the radio button for "ReSharper 2.x IntelliJ IDEA" is selected. When you try your hotkey again, you should get the "Use ReSharper command" versus "Use Visual Studio commands" prompt again.
Wednesday, August 6, 2014
catch errors with jQuery's .ajax
Per the REST spec DELETE and PUT should be implemented in a fire and forget manner. (It is POST and GET which return data.) If you're not going to get anything back upon success however, how will you know if something goes wrong? Well, you can still catch an error in a jQuery .ajax implementation like so:
$.ajax({
type: "DELETE",
url: '/api/Person?identity=' + $('#FlatIdentity').val(),
dataType: 'json',
success: function () {
isBlinkingDeleteAccountButton = false;
window.location = "/home/exit/";
},
error: function (request, status, error) {
var responseText = JSON.parse(request.responseText);
$('#DeleteAccountError').html(responseText.ExceptionMessage);
}
});
My code reaches out to an ASP.NET MVC Web API controller action. I, when applicable, throw exceptions therein like so:
throw new Exception("Sad trombone.");
force jQuery's .ajax to run synchronously with async:false
$.ajax({
type: "DELETE",
url: '/api/Person?identity=' + $('#FlatIdentity').val(),
dataType: 'json',
success: function() {
isBlinkingDeleteAccountButton = false;
},
async: false
});
alert('this is after it all');
Delete a record in an Entity Framework implementation.
public void DeletePerson(Person person)
{
using (var db = new PersonContext())
{
db.People.Attach(person);
db.People.Remove(person);
db.SaveChanges();
}
}
driving CORS through attributes?
http://msdn.microsoft.com/en-us/magazine/dn532203.aspx seems to show off an attribute-based approach to specifying CORS rules at an action at an ASP.NET MVC Web API controller like so:
[EnableCors("http://localhost:55912", "Accept, Origin, Content-Type", "POST",
PreflightMaxAge=600)]
public HttpResponseMessage Post(Resource data)
{
return Request.CreateResponse(HttpStatusCode.OK, data);
}
I haven't tried this stuff yet, but... I'm intrigued.
leading underscores and asterisks in CSS
In the stylesheet I have at http://www.tomjaeschke.com/blog/code.zip one may see:
.swirl
{
width: 141px;
padding-left: 859px;
height: 30px;
padding-top: 527px;
_background-image: url("/images/swirl.gif");
background-repeat: no-repeat;
position: absolute;
z-index: 2;
}
.swirl[class]
{
background-image: url("/images/swirl.png");
}
The leading underscore at _background-image: url("/images/swirl.gif"); means that only Internet Explorer 6 will see the style. A leading asterisk would have the effect of making the style only applicable to Internet Explorer 7 and 6 and of course one may override a style with a leading asterisk with a style with a leading underscore in the name of making a differentiation between an Internet Explorer 7 specific styling and an Internet Explorer 6 specific styling. This trick was taught to me by Dustin Wells himself. Clearly that was some time ago as... well, who worries about this stuff anymore? .swirl[class] will only be seen by browsers BETTER than Internet Explorer 6! In this CSS I am trying to use a transparent .png for a background, but I am failing over to using a transparent .gif for a background (with, sigh, no antialiasing) if I really have to in Internet Explorer 6 where a transparent .png will not be transparent. Old school, eh?
Tuesday, August 5, 2014
read what is at the URL line in JavaScript
In doing a postMessage/addEventListener/receiveMessage messaging means in JavaScript between an iFrame's contents and the page the iFrame itself sits in which is hosted at a different domain name, one may let the iFrame know what domain name is poking at it (a vital piece of information) by talking from the outside to the inside first as seen here or alternatively by handing that data in at the URL line when calling the iFrame content's.
<!DOCTYPE html>
<html>
<body>
<script context="text/javascript">
function receiveMessage(event) {
if (event.origin == "http://bar") {
alert(event.data);
}
};
window.addEventListener("message", receiveMessage, false);
</script>
<p>This page holds an iframe at: "foo"</p>
<iframe name="eye" src="http://bar/index.html?whoisoutside=foo">
</iframe>
</body>
</html>
Make sense of what was handed in like so.
<!DOCTYPE html>
<html>
<body>
<script context="text/javascript">
var urlVariables = window.location.href.substring(window.location.href.indexOf('?')
+ 1, window.location.href.length);
var whoIsOutside;
var cat = {
name: "Patches",
color: "Calico",
about: function() {
return this.name + " is " + this.color;
}
};
function findWhoIsOutside(segment) {
if (urlVariables.indexOf('=') == -1)
{
return null;
} else {
var name = segment.substring(0, segment.indexOf('='));
if(name.toLowerCase() == "whoisoutside") {
return segment.substring(segment.indexOf('=') + 1, segment.length);
} else {
return null;
}
}
};
while (whoIsOutside === undefined) {
if (urlVariables.indexOf('&') == -1)
{
whoIsOutside = findWhoIsOutside(urlVariables);
} else {
var attemptToMatch = findWhoIsOutside(urlVariables.substring(0,
urlVariables.indexOf('&')));
urlVariables = urlVariables.substring(urlVariables.indexOf('&') + 1,
urlVariables.length);
if (attemptToMatch) {
whoIsOutside = attemptToMatch;
}
}
};
top.postMessage(cat.about(), "http://" + whoIsOutside);
</script>
<p>This page sits inside an iframe at: "bar"</p>
</body>
</html>
The second page here is the page inside of the iFrame and the first page is the page that actually holds the iFrame. The first page lives at http://foo/index.html and the second page lives at http://bar/index.html in this example. The second page will hand the string made by cat.about() up to the first page which will then cough it up to view in an alert.
Test the same local IIS web sites you may test at your PC at your iPhone and iPad!
The trick is to get your iOS device to look to your PC's hosts file and then use the hosts file to route requests. You will first need the local IP from your PC and you may get this by opening a command prompt, typing "ipconfig" and making note of the "IPv4 Address" that comes back in the results. Once you have this do the following at your iPhone or iPad:
- Go to "Wi-Fi" under settings.
- You will see a lot of nothing here if the "Wi-Fi" setting is just switched off. Switch it on if it is not on.
- You should see a list of networks. Connect to your workplace's wireless.
- You will either be taken to a screen of settings for the particular wireless network or just stay at the list of all wireless networks depending upon whether or not you've connected to the wireless network before. Either way, you will want to next up get to the settings for the particular wireless network. If you do not fall over there automatically, you may, from the list of all networks, touch the icon at the far right of the line item for your network. This will either look like a lowercase letter i inside of a circle or a greater than sign inside of a circle depending upon how old your iOS is. The act of touching this icon will take you to the settings for the applicable network.
- At the bottom of the settings is an "HTTP Proxy" subsection with three tabs labeled Off, Manual, and Auto. Click on the Manual tab.
- At the "Server" setting, enter your "IPv4 Address" value. It didn't seem to make a difference for worse or better for me if the "Port" setting was empty, zero, or eighty.
- Use the rightward pointing arrow at the top of the settings to walk backwards to the list of all wireless networks. This should save your change and your iOS device should now be using your PC's hosts file first now whenever it tries to find a web site.
- Test your web sites.
polyfill for Internet Explorer versions 6, 7, and 8 for my last blog posting
The page holding the iFrame as specified here would need to be tweaked to be like so:
<!DOCTYPE html>
<html>
<body>
<script context="text/javascript">
var theOtherWorld;
function findTheOtherWorld(world) {
theOtherWorld = world;
};
function reachIntoTheOtherWorld() {
theOtherWorld.postMessage("letmein", "http://bar");
};
function receiveMessage(event) {
if (event.origin == "http://bar") {
alert(event.data);
}
};
if (window.addEventListener) {
window.addEventListener("message", receiveMessage, false);
} else {
window.attachEvent("onmessage", receiveMessage);
};
</script>
<p>This page holds an iframe at: "foo"</p>
<iframe name="eye" src="http://bar/index.html"
onload="findTheOtherWorld(window.eye);">
</iframe>
<div>
<button onClick="reachIntoTheOtherWorld();">reach into the iFrame</button>
</div>
</body>
</html>
The actual content in the iFrame looks like this now:
<!DOCTYPE html>
<html>
<body>
<script context="text/javascript">
var cat = {
name: "Patches",
color: "Calico",
about: function() {
return this.name + " is " + this.color;
}
};
function receiveMessage(event) {
if (event.data == "letmein") {
if (event.origin == "http://foo") {
top.postMessage(cat.about(), "http://foo");
}
}
};
if (window.addEventListener) {
window.addEventListener("message", receiveMessage, false);
} else {
window.attachEvent("onmessage", receiveMessage);
};
</script>
<p>This page sits inside an iframe at: "bar"</p>
</body>
</html>
Monday, August 4, 2014
Talk to and iFrame and back across hosting at two different domain names!
This isn't as easy as I make it seem here. Let's say I have this web page hosted at http://foo/index.html:
<!DOCTYPE html>
<html>
<body>
<script context="text/javascript">
var theOtherWorld;
function findTheOtherWorld(world) {
theOtherWorld = world;
};
function reachIntoTheOtherWorld() {
alert(theOtherWorld.cat.about());
};
</script>
<p>This page holds an iframe at: "foo"</p>
<iframe name="eye" src="http://bar/index.html"
onload="findTheOtherWorld(window.eye);">
</iframe>
<div>
<button onClick="reachIntoTheOtherWorld();">reach into the iFrame</button>
</div>
</body>
</html>
...and let's also say that at http://bar/index.html lives the page nested inside of the iFrame at http://foo/index.html which looks like this:
<!DOCTYPE html>
<html>
<body>
<script context="text/javascript">
var cat = {
name: "Patches",
color: "Calico",
about: function() {
return this.name + " is " + this.color;
}
};
</script>
<p>This page sits inside an iframe at: "bar"</p>
</body>
</html>
Well, then when I press the button it's going to throw up an alert like so, correct?
Wrong! That's not what is going to happen. If I were not trying to reach across from the hosting at one domain name to hosting at another the code above would work great, but alas that's not our circumstance and I'm going to get an error in the console like so:
Uncaught SecurityError: Blocked a frame with origin "http://foo" from accessing a frame with origin "http://bar". Protocols, domains, and ports must match.
I found this online which gives us a solution to this problem. To accomodate the fix, I can refactor my web page with an iFrame to be like so:
<!DOCTYPE html>
<html>
<body>
<script context="text/javascript">
var theOtherWorld;
function findTheOtherWorld(world) {
theOtherWorld = world;
};
function reachIntoTheOtherWorld() {
theOtherWorld.postMessage("letmein", "http://bar");
};
</script>
<p>This page holds an iframe at: "foo"</p>
<iframe name="eye" src="http://bar/index.html"
onload="findTheOtherWorld(window.eye);">
</iframe>
<div>
<button onClick="reachIntoTheOtherWorld();">reach into the iFrame</button>
</div>
</body>
</html>
The web page which sits inside of the iFrame ends up looking like this:
<!DOCTYPE html>
<html>
<body>
<script context="text/javascript">
var cat = {
name: "Patches",
color: "Calico",
about: function() {
return this.name + " is " + this.color;
}
};
function receiveMessage(event) {
if (event.data == "letmein") {
if (event.origin == "http://foo") {
alert(cat.about());
}
}
};
window.addEventListener("message", receiveMessage, false);
</script>
<p>This page sits inside an iframe at: "bar"</p>
</body>
</html>
Hmmm... now we are able to get back info about Patches, our calico cat, from the page within the iFrame, but we are deferring to it to inform us instead of throwing the alert in the page actually holding the iFrame as we had before. If we are going to throw an alert with the info about Patches from the first web page we will need yet another refactoring. How may we round trip data from first outside of the iFrame, then into it, and finally back again? That looks like this:
<!DOCTYPE html>
<html>
<body>
<script context="text/javascript">
var theOtherWorld;
function findTheOtherWorld(world) {
theOtherWorld = world;
};
function reachIntoTheOtherWorld() {
theOtherWorld.postMessage("letmein", "http://bar");
};
function receiveMessage(event) {
if (event.origin == "http://bar") {
alert(event.data);
}
};
window.addEventListener("message", receiveMessage, false);
</script>
<p>This page holds an iframe at: "foo"</p>
<iframe name="eye" src="http://bar/index.html"
onload="findTheOtherWorld(window.eye);">
</iframe>
<div>
<button onClick="reachIntoTheOtherWorld();">reach into the iFrame</button>
</div>
</body>
</html>
...and it also looks like what is below. I may have been able to use event.source below instead of top. event.source was suggested in the blog posting at the link I offer above, but top also worked for me. Whatever.
<!DOCTYPE html>
<html>
<body>
<script context="text/javascript">
var cat = {
name: "Patches",
color: "Calico",
about: function() {
return this.name + " is " + this.color;
}
};
function receiveMessage(event) {
if (event.data == "letmein") {
if (event.origin == "http://foo") {
top.postMessage(cat.about(), "http://foo");
}
}
};
window.addEventListener("message", receiveMessage, false);
</script>
<p>This page sits inside an iframe at: "bar"</p>
</body>
</html>
You will notice that I do not just hand back the cat variable. If I did that I would get this error in the console:
Uncaught DataCloneError: Failed to execute 'postMessage' on 'Window': An object could not be cloned.
The biggest time hole that I fought today in getting this stuff working lay in this error. It stems from the fact that there is a method on cat. If cat only had name and color and not about then it might be transfered as a JSON object to become event.data at the page holding the iFrame, but then, naturally, we would have to create our "Patches is Calico" message another way. There is no way to bring the about method across the wire. I noticed today that JSON.stringify just drops methods off of objects that it serializes to strings. I guess JavaScript methods just do not travel through the eyes of needles very well all and all.
"classes" in JavaScript (and encapsulation, inheritance, and methods too)
By brain tries to juggle the difference in common computer science concepts between C# and JavaScript. Yes, there is not private versus public in JavaScript, but one may still have encapsulation nonetheless by just nesting one function inside of another allowing only the outer function to use the inner function. This touches on three ways to make "classes!" (There is NOT really such a thing as a class in JavaScript.) The first is to just make an instance of a named function like so:
function Orange (valueToMsPacman) {
this.name = "Orange";
this.points = valueToMsPacman;
}
Orange.prototype.description = function() {
return "The " + this.name + " is worth " + this.points + "!";
}
var orange = new Orange(500);
alert(orange.name);
alert(orange.points);
alert(orange.description());
The link I just gave also recommends bolting on function functionality that is never going to vary from instance to instance with the prototype inheritance trick in lieu of recreating it every time an instance of a named function is made (by nesting it in the function). This entails less overhead. I always wondered why I should care about JavaScript's lightweight inheritance and now I know why. You may see the inheritance stuff in action in the code above. Also, I offer a reminder. (I think I have blogged of this before.) A method in JavaScript is a function hanging off of a JSON object as a property like so:
var orange = {
name: "Orange",
points: 500,
description: function() {
return "The " + this.name + " is worth " + this.points + "!";
}
};
alert(orange.name);
alert(orange.points);
alert(orange.description());
The author (Stoyan Stefanov) of the blog post at the link I provide at the very top of this blog posting would also consider the JSON object I just showed off to be a "class." There is also one last way to make a "class" per Mr. Stefanov and that is like so:
var orange = new function() {
this.name = "Orange";
this.points = 500;
this.description = function() {
return "The " + this.name + " is worth " + this.points + "!";
};
};
alert(orange.name);
alert(orange.points);
alert(orange.description());
This is more or less the same thing as the prior example, however commas become semicolons, colons become equals signs, and "this" gets thrown into the mix.
Notepad's quirk of not showing line breaks
...is pretty frustrating. I made line breaks in a .txt file in Notepad, pushed the file up to Github, pulled it down elsewhere, and upon looking at it in Notepad, my line breaks where gone! Or were they? My application was still able to split a string read from the file's contents on the line breaks. If I look at the copy in Wordpad I see the line breaks. This just suggests this is merely a quirk of Notepad rather than anything I did wrong. It also recommends copying to Word (from Notepad) and then back to Notepad to see the line breaks. I tried as much and it works! ...meaning that the line breaks were always there to begin with. Whatever.
Firefox and Chrome update themselves more or less and hence there is not a need to test prior versions of Firefox and Chrome as one might Internet Explorer.
Internet Explorer is another thing. As long as we keep using Windows XP, Internet Explorer 6 will be with us.
Saturday, August 2, 2014
AJAX without jQuery
...doesn't seem that hard if you don't have to support Internet Explorer 9. It may be done like so with JavaScript alone:
<!DOCTYPE html>
<html>
<body>
<script context="text/javascript">
var myping=new XMLHttpRequest();
myping.open("GET", "http://opendoor/api/square?number=7", true);
myping.setRequestHeader("Content-type","application/x-www-form-urlencoded");
myping.setRequestHeader("Accept", "application/json; charset=utf-8");
myping.onload = function (data) {
alert(data.currentTarget.response);
console.log(data.currentTarget.response);
}
myping.send();
</script>
</body>
</html>
"What's at opendoor/api/square then?" you ask? It is an ASP.NET MVC Web API controller action which looks like this:
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace OpenDoor.Controllers
{
public class SquareController : ApiController
{
public HttpResponseMessage Get(string number)
{
string answer;
decimal interpretation = 0;
bool isDecimal = decimal.TryParse(number, out interpretation);
if (isDecimal)
{
answer = interpretation + " squared is: " + (interpretation * interpretation);
} else {
answer = "The value provided was not a number.";
}
var response = Request.CreateResponse<string>(HttpStatusCode.OK, answer);
response.Headers.Add("Access-Control-Allow-Origin","*");
return response;
}
}
}
The following links helped me figure this out and also offered some insights as to how to polyfill older versions of IE.
Friday, August 1, 2014
JSONP
This suggests that you'd use the jsonp dataType (in a jQuery .ajax implementation) in lieu of the json dataType when reaching out to a web service that returns JSON at a different domain in a cross-origin attempt to drink data from afar.
It also suggests that jsonp "wraps the returned JSON data in a function call" apparently allowing for the cross-origin stuff to work instead of just blowing up as it would if merely json was used.
The handlers and modules in Web.config!
I really haven't thought that much about what the modules and handlers do. I experimented with them some today however. I set up system.webServer in the configuration of Web.config to hold the following:
<system.webServer>
<modules>
<add name="SessionTimeout" type="HandleThis.Magic.LifeAndDeathModule"
preCondition="managedHandler" />
</modules>
<handlers>
<add name="LifeAndDeathHandler" verb="*" path="Speak.ashx"
type="HandleThis.Magic.LifeAndDeathHandler" />
</handlers>
</system.webServer>
I believe this would work just fine in system.web too, but of course system.web is just for IIS6 hosting. Let's look at what our token module and handler do. Here is the module first:
using System;
using System.Runtime.Caching;
using System.Web;
namespace HandleThis.Magic
{
public class LifeAndDeathModule : IHttpModule
{
public void Init(HttpApplication httpApplication)
{
CacheSomething("life", "I live! ");
}
public void Dispose()
{
CacheSomething("death", "I die! ");
}
private void CacheSomething(string key, string value)
{
if (MemoryCache.Default[key] != null)
{
MemoryCache.Default.Remove(key);
}
CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();
cacheItemPolicy.AbsoluteExpiration = DateTime.Now +
TimeSpan.FromMinutes(30);
MemoryCache.Default.Add(new CacheItem(key, value), cacheItemPolicy);
}
}
}
The modules will run all the time whenever one spins up the application or whenever one just changes the URL within the application. Therefore, you can sort of do some AOP stuff within modules. For example, if I have a web form with a code behind like so:
using System;
using System.Runtime.Caching;
using System.Web.UI;
namespace HandleThis
{
public partial class _Default : Page
{
public string MyState;
protected void Page_Load(object sender, EventArgs e)
{
MyState = MemoryCache.Default["life"] as string +
MemoryCache.Default["death"];
}
}
}
...I may in the web form expose some of the stuff my module put in the cache by just using some markup like this:
<h1><%= MyState %></h1>
When the app first spins up the H1 tag will say "I live!" and after some time has passed and the garbage collector has done its thing one may refresh the browser and instead see "I live! I die!" There will never be a time when at the very least "I live!" is not displayed. In setting breakpoints, I witnessed the application, upon spinning up, call the Init method on the module three times before the Page_Load method on the web form's code behind (the code behind for Default.aspx, the default first web form loaded) was called. Our handler will not run automatically by itself like our module so we must call out to it. Putting a script tag like this in our web form will do the trick:
<script src="http://localhost:65413/Speak.ashx?instructions=yell" type="text/javascript">
</script>
Here is our handler:
using System.Runtime.Caching;
using System.Web;
namespace HandleThis.Magic
{
public class LifeAndDeathHandler : IHttpHandler
{
public void ProcessRequest(HttpContext httpContext)
{
string instructions = httpContext.Request.QueryString["instructions"];
string message = MemoryCache.Default["life"] as string +
MemoryCache.Default["death"];
if (instructions == "yell") message = message.ToUpper();
httpContext.Response.Write("alert('" + message + "');");
}
public bool IsReusable
{
get { return false; }
}
}
}
As you can see, it will return some JavaScript for the script tag!
I finally got to use my Plantronics headset in a meeting by phone at work today.
It worked great! This was another something I picked up at Fry's Electronics. I bless this product as I bless the JVC Sport Headphones I got there too.