Jag har nu påbörjat min första IPA (Indian Pale Ale).
Det är enkelt att göra hemma i köket och det behöver bara stå sedan i vanlig rumstemperatur i några veckor. Jag köpte mitt första kit från http://olkassen.se
Ska bli spännande att se hur bra det blev om fyra veckor då det kan avnjutas.
Se min film om hur jag gjorde här:
https://youtu.be/G-UbbWB2Qfs
söndag 12 april 2015
onsdag 10 december 2014
Grunt - Get started
- Install Node Package Manager (npm)
- Open Nodejs Command Prompt (as admin) and go to folder of your project!
- Create a file in root of your project called package.json that looks like:
{
"name": "Pers-FrontEndStuff",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.5",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-nodeunit": "~0.4.1",
"grunt-contrib-uglify": "~0.5.0"
}
}
- Make a file in root of your project called Gruntfile.js that looks like:
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
dist: {
src: ['static/js_grunt_src/scriptsA.js', 'static/js_grunt_src/scriptsB.js'],
dest:'static/js_grunt_src/_scripts.js'
}
},
uglify: {
static_folder: {
files: {
'static/js/scripts.min.js': ['static/js_grunt_src/_scripts.js']
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.registerTask('default', ['concat', 'uglify', 'jshint']);
};
- Install Grunt by following http://gruntjs.com/getting-started, basically:
npm install grunt --save-dev
- Install each plugin you want like concat (merge js-files together into one) and uglify (minification of js-file) jshint (js-file validation), like:
npm install grunt-contrib-concat
npm install grunt-contrib-uglify
npm install grunt-contrib-jshint
- Now you can run each task (like the concat task) with command:
grunt concat
- Run 2 tasks with command:
grunt concat uglify
lördag 1 november 2014
Node.js, Node Package Manager (NPM) and Bower
Snabb guide vad som behövs för att installera och komma igång med Bower med hjälp av Node.js och Node Package Manager (NPM) i Windows.
Börja med att installera GiT från:
http://git-scm.com/download/win
Se till att GiT finns i din PATH genom att högerklicka på "Den här datorn" i utforskaren och välja "Egenskaper".
På Windows 7 finns länken "Ändra inställningar" en bit ner till höger på det fönster som öppnades.
När du klickar på den länken öppnas ett nytt fönster och där väljer du fliken "Avancerat" och sedan klickar du på knappen "Miljövariabler" (Environment variables).
Leta upp PATH under antingen användarvariabler eller systemvariabler och lägg till sökvägarna för GiT (kontrollera att de stämmer på just din dator) efter de sökvägar som eventuellt redan finns där:
C:\Program Files (x86)\Git\bin;C:\Program Files (x86)\Git\cmd
Installera sedan Node.js från:
http://nodejs.org/download/
Skapa en testmapp någonstans på din dator.
Öppna Windows kommandotolken eller PowerShell och ställ dig i din nya testmapp.
När du installerade Node.js så inkluderades Node Package Manager så med hjälp av dess kommando npm kan du nu installera Bower.
npm install -g bower
Skapa en ny fil din testmapp som heter bower.json och som innehåller följande:
{
"name": "my-project"
}
Nu kan du exempelvis installera jQuery via kommandot:
bower install jquery --save
Flaggan --save betyder att den även lägger till och sparar denna referens i bower.json.
Tips på var du kan läsa mer.
Börja med att installera GiT från:
http://git-scm.com/download/win
Se till att GiT finns i din PATH genom att högerklicka på "Den här datorn" i utforskaren och välja "Egenskaper".
På Windows 7 finns länken "Ändra inställningar" en bit ner till höger på det fönster som öppnades.
När du klickar på den länken öppnas ett nytt fönster och där väljer du fliken "Avancerat" och sedan klickar du på knappen "Miljövariabler" (Environment variables).
Leta upp PATH under antingen användarvariabler eller systemvariabler och lägg till sökvägarna för GiT (kontrollera att de stämmer på just din dator) efter de sökvägar som eventuellt redan finns där:
C:\Program Files (x86)\Git\bin;C:\Program Files (x86)\Git\cmd
Installera sedan Node.js från:
http://nodejs.org/download/
Skapa en testmapp någonstans på din dator.
Öppna Windows kommandotolken eller PowerShell och ställ dig i din nya testmapp.
När du installerade Node.js så inkluderades Node Package Manager så med hjälp av dess kommando npm kan du nu installera Bower.
npm install -g bower
Skapa en ny fil din testmapp som heter bower.json och som innehåller följande:
{
"name": "my-project"
}
Nu kan du exempelvis installera jQuery via kommandot:
bower install jquery --save
Flaggan --save betyder att den även lägger till och sparar denna referens i bower.json.
Tips på var du kan läsa mer.
Etiketter:
Bower,
Javascript,
jQuery,
Node.js,
Programmering
lördag 2 augusti 2014
Returnera innehåll som fil i MVC
För att returnera en fil för nedladdning i MVC, antingen genom att returnera en fil på disk eller ett textinnehåll i en variabel, så gör man bara en Action som ser på följande vis.
Sen kan man själv variera mimeType beroende på vilken typ av fil det är såklart.
Sen kan man själv variera mimeType beroende på vilken typ av fil det är såklart.
public FileContentResult DownloadFile()
{
string fileName = "minfil.txt";
byte[] doc = System.IO.File.ReadAllBytes(@"C:\path\...\" + fileName);;
//byte[] doc = Encoding.UTF8.GetBytes(myStringVariable);
string mimeType = "text/plain";
Response.AppendHeader("Content-Disposition", "attachment; filename=" + fileName);
return File(doc, mimeType);
}
torsdag 31 juli 2014
Simpel autocomplete funktionalitet - jQuery
Tänkte visa hur jag gjort en simpel variant av autocomplete som man kan använda där man vill kunna välja bland ett antal förutbestämda värden.
_searchTextBoxControlId = ID på textfältet där användaren ska skriva sitt sökord.
_tagAutoCompleteListId = ID på den DIV-tagg som agerar "behållare" för alla värden som användaren kan välja bland. CSS på denna bör vara "display:none" initialt.
showMessage() är en valfri metod där man kan skriva ut info till användaren, t.ex. i en informationsruta.
Kod att köra vid sidladdning:
Kod som knyts till texfältet för sökning:
_searchTextBoxControlId = ID på textfältet där användaren ska skriva sitt sökord.
_tagAutoCompleteListId = ID på den DIV-tagg som agerar "behållare" för alla värden som användaren kan välja bland. CSS på denna bör vara "display:none" initialt.
showMessage() är en valfri metod där man kan skriva ut info till användaren, t.ex. i en informationsruta.
Kod att köra vid sidladdning:
var initTagAutoComplete = function() {
$.ajax({
type: 'POST',
url: '/your/url/to/fetch/arrayofstrings',
dataType: 'json',
beforeSend: function (jqXhr, settings) {
showMessage('Initilizing autocomplete...');
},
success: function (data, textStatus, jqXhr) {
//data should be expected to be returned as ['astring', 'anotherstring', 'yetanotherstring', ...]
$(_tagAutoCompleteListId).empty();
$.each(data, function(idx) {
$(_tagAutoCompleteListId).append('<div class="autocomplete-item"><a data-autocomplete="' + idx + '" href="#" onclick="event.preventDefault;$(\'' + _searchTextBoxControlId + '\').val(\'' + data[idx] + '\');$(\'' + _tagAutoCompleteListId + '\').fadeOut(\'slow\')">' + data[idx] + '</a></div>');
});
showMessage('');
},
error: function (jqXhr, textStatus, errorThrown) {
showMessage('Technical error!');
}
});
Kod som knyts till texfältet för sökning:
$(_searchTextBoxControlId).keyup(function (event) {
var searchWord = $(_searchTextBoxControlId).val();
$(_tagAutoCompleteListId).fadeIn('slow');
$('a[data-autocomplete]').each(function (idx) {
$('a[data-autocomplete="' + idx + '"]').parent().hide();
var tagValue = $('a[data-autocomplete="' + idx + '"]').text();
if (tagValue.toLowerCase().indexOf(searchWord.toLowerCase()) == 0) {
$('a[data-autocomplete="' + idx + '"]').parent().show();
}
});
});
tisdag 8 juli 2014
Håll koll på versionerna
Det är ofta man behöver veta eller undersöka vilka versioner som gäller och finns tillgängliga för olika plattformar och ramverk.
Här är några bra länkar att ha koll på som hjälper till:
Här är några bra länkar att ha koll på som hjälper till:
lördag 31 maj 2014
Skapa iframeinnehåll dynamiskt med Javascript
Denna kodsnutt visar på hur man på ett enkelt sätt kan skapa en iframe med javascript, som i sin tur skapar upp HTML-dokumentet som ska visas i iframen istället för att länka till en befintlig sida.
Visar dessutom hur man t.ex. kan lägga till en scripttagg i den skapade iframesidan.
Visar dessutom hur man t.ex. kan lägga till en scripttagg i den skapade iframesidan.
<div id="my-iframe-container"></div>
<script>
var iframe = document.createElement('iframe');
iframe.width = '539px';
iframe.height = '380px';
iframe.scrolling = 'no';
var html = "<!DOCTYPE html>\n<head>\n<title>Test</title>\n</head>\n<body>\n";
html += "<div>Hello World!</div>";
html += "\n</body>\n</html>";
document.getElementById('my-iframe-container').appendChild(iframe);
iframe.contentWindow.document.open();
iframe.contentWindow.document.write(html);
iframe.contentWindow.document.close();
var headTag = iframe.contentWindow.document.getElementsByTagName('head')[0];
var s1 = iframe.contentWindow.document.createElement("script");
s1.type = "text/javascript";
s1.charset = 'UTF-8';
s1.async = true;
s1.id = 'another-script';
s1.src = 'http://mydomain.com/another.js';
headTag.appendChild(s1);
</script>
onsdag 26 mars 2014
Generiska klasser i .Net
Bra film om du vill lära dig grunden i hur man skapar generiska klasser i .Net:
http://youtu.be/2LfoxTyWzVM
http://youtu.be/2LfoxTyWzVM
lördag 7 december 2013
IIFE i Javascript
I Javascript finns något man kallar IIFE (immediately invoked function expression) vilket innebär att det är en funktion, precis som vilket Javascript-funktion som helst, men den körs direkt vid sidladdning, och inte genom ett anrop exempelvis genom att klicka på en knapp eller liknande.
Fördelen är att alla variabler lever endast inne i funktionen, även det i.o.f. precis som vanligt men det är användbart när man vill ha kod på en sida som ska köras direkt vid sidladdning och inte råka "krocka" med andra variabelnamn etc. på sidan.
Fördelen är att alla variabler lever endast inne i funktionen, även det i.o.f. precis som vanligt men det är användbart när man vill ha kod på en sida som ska köras direkt vid sidladdning och inte råka "krocka" med andra variabelnamn etc. på sidan.
<script>
// Detta är ett "Immediately-Invoked Function" uttryck
(function() {
var foo = "Hejsan";
})();
alert(foo); // undefined!
</script>
söndag 20 oktober 2013
Gör en egenskap read-only i EPiServer
Gör en Custom Property Type som du kallar PropertyReadOnlyString som ärver av PropertyString.
Lägg till ett "disabled" attribut när Edit Control skapas.
Samma kan göras för PropertyLongString, PropertyNumber, etc.
Detta behöver göras i CreateEditControls() för din kontroll klass.
Detta behöver göras i CreateEditControls() för din kontroll klass.
public override void CreateEditControls()
{
this.EditControl.Attributes.Add("disabled", "disabled");
}
tisdag 3 september 2013
WebAPI i WebForms, Visual Studio 2010 .NET 4.0
Jag sökte runt för att hitta hur man sätter upp WebAPI i ett WebForms-projekt och hittade en del sidor som pekade på samma sätt:
Jag hade stora problem med att fatta var RouteTable.Routes.MapHttpRoute kom ifrån, trodde att det var System.Web.Http såklart men icke?!
Till slut kom jag på genom att studera ett annat fungerande WebAPI-project att jag skulle skriva:
Observera också att du först via NuGet Package Console Manager måste ha installerat:
using System.Web.Http;
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
Jag hade stora problem med att fatta var RouteTable.Routes.MapHttpRoute kom ifrån, trodde att det var System.Web.Http såklart men icke?!
Till slut kom jag på genom att studera ett annat fungerande WebAPI-project att jag skulle skriva:
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
Observera också att du först via NuGet Package Console Manager måste ha installerat:
Install-Package AspNetWebApi
onsdag 28 november 2012
Web API Dependency Resolver
Denna artikel förklarar på ett bra sätt hur man använder Dependency Resolver i en MVC Web API Controller-klass.
Web API för nybörjare
Denna artikel ger en bra start att förstå Web API som introducerades i .NET MVC 4, och sedan även gå vidare att läsa denna artikel.
måndag 26 november 2012
Enkelt jQuery Ajax anrop i MVC
Att med hjälp av jQuery/Ajax anropa en C#-metod i ett MVC-projekt som returnerar Json är enkelt. I följande exempel ligger metoden i en controllerklass som heter HomeController, vilket ger URL:en /home/helloworld/ att anropa.
På sidan som ska anropa metoden har jag en DIV med id="responseResult" och lägger följande jQuery-kod.
Som bonus la jag till en fade-effekt efter 2 sekunder på resultatet.
Om man bara vill returnera en vanlig sträng kan koden i HelloWorld() se ut:
Då skrivs resultatet ut med endast "data" såhär:
public ActionResult HelloWorld()
{
return Json(new { Firstpart = "Hello", Secondpart = "World" }, JsonRequestBehavior.AllowGet);
}
På sidan som ska anropa metoden har jag en DIV med id="responseResult" och lägger följande jQuery-kod.
$(document).ready(function () {
$.ajax({
url: '/home/helloworld',
success: function (data) {
$('#responseResult').html('Resultat: ' + data.Firstpart + ' ' + data.Lastpart).delay(2000).fadeIn('slow');
},
error: function (data) {
alert('Error: Ajax call failed.');
}
});
});
Som bonus la jag till en fade-effekt efter 2 sekunder på resultatet.
Om man bara vill returnera en vanlig sträng kan koden i HelloWorld() se ut:
public ActionResult HelloWorld()
{
return Content("Hello World");
}
Då skrivs resultatet ut med endast "data" såhär:
$(document).ready(function () {
$.ajax({
url: '/home/helloworld',
success: function (data) {
$('#responseResult').html('Resultat: ' + data).delay(2000).fadeIn('slow');
},
error: function (data) {
alert('Error: Ajax call failed.');
}
});
});
fredag 16 november 2012
SimpleMembershipProvider WebSecurity.InitializeDatabaseConnection
Kom i kontakt med autentisering med hjälp av WebMatrix.WebData.SimpleMembershipProvider för att sköta inloggning och administration av användarkonton, men man gör det helst med hjälp av hjälpklassen WebSecurity.
Skapar man ett nytt default MVC 4 projekt i Visual Studio 2012 så skapas allt detta upp åt dig men med en lokal databasfil.
Om man som jag direkt vill ändra detta till att fungera mot sin SQL Server databas är det enkelt. Dock stötte jag på ett litet problem direkt om hur connectionsträngen skulle se ut för att metoden WebSecurity.InitializeDatabaseConnection() ska fungera.
Jag hade glömt att sätta attributet "providerName" till "System.Data.SqlClient":
<add name="MinDatabasConnection" providerName="System.Data.SqlClient" connectionString="Data Source=minDBserver\sqlexpress2012;Initial Catalog=DatabasNamnet;User ID=minDBuser;Password=*****" />
Sedan om inte de korrekta tabellerna redan existerar (vid ett nystartat projekt) så kan de begäras att skapas automatiskt via "autoCreateTable: true":
WebSecurity.InitializeDatabaseConnection("MinDatabasConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
Skapar man ett nytt default MVC 4 projekt i Visual Studio 2012 så skapas allt detta upp åt dig men med en lokal databasfil.
Om man som jag direkt vill ändra detta till att fungera mot sin SQL Server databas är det enkelt. Dock stötte jag på ett litet problem direkt om hur connectionsträngen skulle se ut för att metoden WebSecurity.InitializeDatabaseConnection() ska fungera.
Jag hade glömt att sätta attributet "providerName" till "System.Data.SqlClient":
<add name="MinDatabasConnection" providerName="System.Data.SqlClient" connectionString="Data Source=minDBserver\sqlexpress2012;Initial Catalog=DatabasNamnet;User ID=minDBuser;Password=*****" />
Sedan om inte de korrekta tabellerna redan existerar (vid ett nystartat projekt) så kan de begäras att skapas automatiskt via "autoCreateTable: true":
WebSecurity.InitializeDatabaseConnection("MinDatabasConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
söndag 11 november 2012
XML serialisering av C# objekt
Detta exempel är en bra början att lära sig hur XML serialisering fungerar.
Om man t.ex. vill spara ner ett eller flera objekt till en XML-fil för att senare läsa tillbaka den igen.
Om man t.ex. vill spara ner ett eller flera objekt till en XML-fil för att senare läsa tillbaka den igen.
fredag 9 november 2012
SignalR chat example
Nyheter i VS2012 och .NET 4.5
Bra artikel av Scott Hanselman med videos om nyheterna i Visual Studio 2012 och .NET 4.5
Läs/se den här.
Läs/se den här.
torsdag 8 november 2012
.Net using Javascript/ASMX-Webservice
Snabb demo av hur javascript och WebService(asmx)-anrop funkar i .NET
Fil Demo.asmx
På samma ASPX-sida som du kommer ha ditt javascript, behöver du lägga till en ScriptManager:
För denna demo lägger jag till en SPAN-tagg där resultatet från anropet kommer visas:
Själva javascriptanropet kan nu göras på följande sätt:
Fil Demo.asmx
namespace TestProject.AsmxServices
{
/// <summary>
/// Summary description for Demo
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class Demo : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
}
På samma ASPX-sida som du kommer ha ditt javascript, behöver du lägga till en ScriptManager:
<asp:ScriptManager runat="server">
<Services>
<asp:ServiceReference Path="/AsmxServices/Demo.asmx" />
</Services>
</asp:ScriptManager>
För denna demo lägger jag till en SPAN-tagg där resultatet från anropet kommer visas:
<span id="asmxOutPut" style="font-weight: bold;"></span>
Själva javascriptanropet kan nu göras på följande sätt:
TestProject.AsmxServices.Demo.HelloWorld(_onCallbackSuccess, _onRequestFailed);
function _onCallbackSuccess(result, userContext) {
document.getElementById('asmxOutPut').innerHTML = result;
}
function _onRequestFailed(result, userContext) {
alert('Request failed');
}
tisdag 6 november 2012
Cache av resultat från klassmetoder
I många klassmetoder så gör man tunga databasfrågor eller andra prestandakrävande operationer som ofta resulterar i samma resultat eftersom inget har ändrats i datat sedan sist denna metod kördes.
Då kan det vara en bra idé att resultatet läggs i cachminnet under en tidsperiod som man tycker är rimligt.
Låt säga att att en metod efterfrågas varje gång första sidan av din webbplats anropas, och denna metod kräver en eller flera databasanrop för att kunna presentera resultatet på sidan. Men eftersom datat för sidan uppdateras i regel som oftast kanske bara en gång var 5:e minut, eller ännu mer sällan så räcker det med att hämta datat en gång från databasen och sedan låta det datat vara ok att presentera (från cacheminnet) på första sidan i, låt säga en minut, oavsett om datat har uppdaterats i databasen.
I följande fåniga exempel visar jag hur man kan cache'a resultatet av en klass olika metoder med olika unika strängnycklar som identifierar resultatet beroende på klass-, metodnamn och metodens olika inparametrar.
Först har jag en hjälpklass med metoden GetCacheKey() som kan användas för alla olika klasser:
På sidan har jag sedan placerat en Literal kallas litOut.
Jag har också skapat en liten Car-klass som har en metod GetCarStamp() som ger tillbaka en specifik sträng för objektet.
Vi ponerar att denna metod kräver prestandakrävande databasanrop så därför är värdet lagrat i cacheminnet i 1minut innan man återigen måste läsa upp det från databasen.
Page_Load metoden ser ut som följer:
Man skulle då få tillbaka strängen "ABC123BLUE" i en minut tills cachen släpper, även om färgen eller registreringsnumret eventuellt har ändrats i databasen under denna tid.
På detta vis kan man göra likadant för alla andra prestandakrävande metoder som klassen eventuellt innehåller och spara dess resultat i cachen med klassnamn (ClassCacheKey) och metodnamn som unik identifierare.
I min Helper-fil har jag lagt till följande statiska metoder:
Och min Car-klass ser nu ut såhär:
Så cachen för GetCarStamp() släpper inte förrän färgen ändras via UpdateCarColor(), eller att applikationen startas om.
Vill man att den ändå ska släppa efter en viss tid så är det bara att byta ut Cache.NoAbsoluteExpiration till det värde man önskar.
Då kan det vara en bra idé att resultatet läggs i cachminnet under en tidsperiod som man tycker är rimligt.
Låt säga att att en metod efterfrågas varje gång första sidan av din webbplats anropas, och denna metod kräver en eller flera databasanrop för att kunna presentera resultatet på sidan. Men eftersom datat för sidan uppdateras i regel som oftast kanske bara en gång var 5:e minut, eller ännu mer sällan så räcker det med att hämta datat en gång från databasen och sedan låta det datat vara ok att presentera (från cacheminnet) på första sidan i, låt säga en minut, oavsett om datat har uppdaterats i databasen.
I följande fåniga exempel visar jag hur man kan cache'a resultatet av en klass olika metoder med olika unika strängnycklar som identifierar resultatet beroende på klass-, metodnamn och metodens olika inparametrar.
Först har jag en hjälpklass med metoden GetCacheKey() som kan användas för alla olika klasser:
namespace CacheTestProject.Helpers
{
public class Helper
{
public static string GetCacheKey(string className, string methodName, params string[] parameters)
{
return className + "-" + methodName + "-" + string.Join("-", parameters);
}
}
}
På sidan har jag sedan placerat en Literal kallas litOut.
Jag har också skapat en liten Car-klass som har en metod GetCarStamp() som ger tillbaka en specifik sträng för objektet.
Vi ponerar att denna metod kräver prestandakrävande databasanrop så därför är värdet lagrat i cacheminnet i 1minut innan man återigen måste läsa upp det från databasen.
public class Car
{
private const string ClassCacheKey = "Car";
public string RegNumber { get; set; }
public string Color { get; set; }
public Car(string regnr, string color)
{
RegNumber = regnr;
Color = color;
}
// EXAMPLE METHOD 1 without cachedependency!
public string GetCarStamp(bool withRegNumber, bool withColor)
{
string cacheKey = Helper.GetCacheKey(
ClassCacheKey,
"GetCarStamp",
RegNumber);
string data = (string)HttpRuntime.Cache.Get(cacheKey);
if (!string.IsNullOrEmpty(data))
{
return data;
}
//Call for the performance demanding method as nothing is in the cache!
data = GetCarStampFromDatabase();
HttpRuntime.Cache.Insert(
cacheKey,
data,
null,
DateTime.Now.AddSeconds(60),
Cache.NoSlidingExpiration);
return data;
}
//Simulate a performance demanding method that we want to
//avoid calling as much as possible
private string GetCarStampFromDatabase()
{
var regNumber = (withRegNumber) ? RegNumber : string.Empty;
var color = (withColor) ? Color : string.Empty;
return string.Format("{0}{1}", RegNumber, color);
}
}
Page_Load metoden ser ut som följer:
protected void Page_Load(object sender, EventArgs e)
{
Car MyCar1 = new Car("ABC123", "BLUE");
litOut.Text = MyCar1.GetCarStamp();
}
Man skulle då få tillbaka strängen "ABC123BLUE" i en minut tills cachen släpper, även om färgen eller registreringsnumret eventuellt har ändrats i databasen under denna tid.
På detta vis kan man göra likadant för alla andra prestandakrävande metoder som klassen eventuellt innehåller och spara dess resultat i cachen med klassnamn (ClassCacheKey) och metodnamn som unik identifierare.
Med Dependency
Om man istället vill att resultatet ska ligga kvar i cachen så länge som inte någonting ändras, alltså att resultatet ska invalideras vid någon form av uppdatering på objektet, kan man justera koden till något i stil med nedanstående.I min Helper-fil har jag lagt till följande statiska metoder:
public static string GetCacheDependencyKey(string className, string SomeUniqueId)
{
return className + "-CacheDepKey-" + SomeUniqueId;
}
public static CacheDependency GetCacheDependency(string className, string SomeUniqueId)
{
//Get unique identification key for the dependency
string DependencyKey = GetCacheDependencyKey(className, SomeUniqueId);
//If it is not already in the cache, add it!
if (HttpRuntime.Cache.Get(DependencyKey) == null)
{
HttpRuntime.Cache.Insert( //HttpRuntime.Cache.Insert will replace object in cache, which HttpRuntime.Cache.Add does not!
DependencyKey,
string.Empty,
null,
Cache.NoAbsoluteExpiration,
Cache.NoSlidingExpiration);
}
//Then create a dependency that tells to depend on the cacheitem with key "DependencyKey"
return new CacheDependency(
null,
new[] { DependencyKey }
);
}
Och min Car-klass ser nu ut såhär:
public class Car
{
private const string ClassCacheKey = "Car";
public string RegNumber { get; set; }
public string Color { get; set; }
public Car(string regnr, string color)
{
RegNumber = regnr;
Color = color;
}
public void UpdateCarColor(string newColor)
{
Color = newColor;
HttpRuntime.Cache.Remove(
Helper.GetCacheDependencyKey(
ClassCacheKey, RegNumber
)
);
}
// EXAMPLE METHOD 1 without cachedependency!
public string GetCarStamp()
{
string cacheKey = Helper.GetCacheKey(
ClassCacheKey,
"GetCarStamp",
RegNumber);
string data = (string)HttpRuntime.Cache.Get(cacheKey);
if (!string.IsNullOrEmpty(data))
{
return data;
}
//Call for the performance demanding method...
data = GetCarStampFromDatabase();
HttpRuntime.Cache.Insert(
cacheKey,
data,
Helper.GetCacheDependency(ClassCacheKey, RegNumber),
Cache.NoAbsoluteExpiration,
Cache.NoSlidingExpiration);
return data;
}
//Simulate a performance demanding method that we want to
//avoid calling as much as possible
private string GetCarStampFromDatabase()
{
return string.Format("{0}{1}", RegNumber, Color);
}
}
Så cachen för GetCarStamp() släpper inte förrän färgen ändras via UpdateCarColor(), eller att applikationen startas om.
Vill man att den ändå ska släppa efter en viss tid så är det bara att byta ut Cache.NoAbsoluteExpiration till det värde man önskar.
Prenumerera på:
Inlägg (Atom)