I installed MonoDevelop from Add/Remove... which did not install all addins I wanted.
Basically I was searching how to install NUnit addin for MonoDevelop. There's a FAQ entry on how to enable it, but it is not very useful, though I did the last bit, creating symbolic link.
Anyway, here's how to install it on Ubuntu:
sudo apt-get install monodevelop-nunit
If you just type
sudo apt-get install monodevelop-
and press Tab key twice it will list you all available addins. One very useful is monodevelop-versioncontrol,
Useful links:
Using NUnit with MonoDevelop
Using Subversion with MonoDevelop
Archived Posts
Displaying posts 11 - 20 of 36
This info relates to Arch Linux and configuration of MySQL to use custom data folder. I followed instructions to install MySQL on ArchWiki. It worked like a charm, everything was working perfectly, until I tried to change data folder. Now, probably important thing to say is that I setup rc.conf to automatically start mysqld daemon. Google did not help this time :( since whatever I tried did not work. Even MySQL official documentation was of no help. Setting datadir in my.cnf did not help. But finally I found solution, and it was super easy:
Edit file: /etc/conf.d/mysqld
And enter your data folder there (/data/mysql in my case):
MYSQLD_ROOT="/data/mysql"
After that it worked. I don't know if this is Arch Linux specific, but I hope this will help someone not to loose as much time I did figuring out.
Edit file: /etc/conf.d/mysqld
And enter your data folder there (/data/mysql in my case):
MYSQLD_ROOT="/data/mysql"
After that it worked. I don't know if this is Arch Linux specific, but I hope this will help someone not to loose as much time I did figuring out.
This is a short instruction how to use Thoth with Heroku. Thoth is a Ruby blog engine, and Heroku is a Ruby hosting platform - there is a convenient free hosting plan. Instructions are targeted towards the latest version of Thoth - 0.3.0.
I'll keep this brief however, first goes disclaimer:
I don't develop in Ruby, I haven't done anything in Ruby yet. All I know about Ruby and Rails is from a book I read long time ago, going through it lightning fast without much retention. There are possible better ways to do this however this approach works. Anyhow, no guarantees.
Get and install the latest version
First of all there is no official 0.3.0 release, or at least I could not find it. Version 0.2.1 did not work on my machine so I had to get the latest version of code, created a gem out of it, installed it and it worked fine after that. Instructions how to get the latest version are at the Thoth homepage.
Create a thoth site
On the same page are instructions how to run it. Create a site, give it whatever name, you'll need to copy those file later on to your heroku application. After following all instructions you can test your new thoth blog.
Create a heroku app
Create your heroku application following instructions from the quick start. You'll need to install git and setup ssh public key. Create heroku application, copy all files from your previously created thoth site, initialize git repository and add files to git. Now everything is practicaly the same as in the quick start - except I could not create thoth site into already existing folder.
Now goes exciting stuff - how to make this really work on heroku.
Getting it all to work
Since there isn't official 0.3.0 version of thoth we need to unpack it into vendor/gems folder of our heroku application first. Then config.ru has to be fixed so that version of thoth is used:
Now specify all required gems. You can read detailed instructions on installing gems on heroku or just create .gems file with following contents:
innate --version 2009.06.12
ramaze --version 2009.06.12
cssmin
jsmin
sanitize
Fix thoth.config file to use correct database connection:
db: <%= ENV['DATABASE_URL'] || ('sqlite:///'+ (Thoth::HOME_DIR) +'/db/live.db') %>
It's postgresql but it seems to be working for now. Another setting needs to be changed and that is url:
# Base URL of your site. This is necessary in order for Thoth to know how
# to construct links. Be sure to set this correctly or links may not work.
url: http://someappname.heroku.com/
Now everything is almost ready, the only thing left is database. You need to run thoth --migrate to crate ./db/live.db sqlite database. Then push it to heroku following instructions, basically one command - something like: heroku db:push sqlite://db/live.db
After this you can push the whole application to heroku and it should work.
Peace of cake, now you have your free personal blog in Ruby.
I'll keep this brief however, first goes disclaimer:
I don't develop in Ruby, I haven't done anything in Ruby yet. All I know about Ruby and Rails is from a book I read long time ago, going through it lightning fast without much retention. There are possible better ways to do this however this approach works. Anyhow, no guarantees.
Get and install the latest version
First of all there is no official 0.3.0 release, or at least I could not find it. Version 0.2.1 did not work on my machine so I had to get the latest version of code, created a gem out of it, installed it and it worked fine after that. Instructions how to get the latest version are at the Thoth homepage.
Create a thoth site
On the same page are instructions how to run it. Create a site, give it whatever name, you'll need to copy those file later on to your heroku application. After following all instructions you can test your new thoth blog.
Create a heroku app
Create your heroku application following instructions from the quick start. You'll need to install git and setup ssh public key. Create heroku application, copy all files from your previously created thoth site, initialize git repository and add files to git. Now everything is practicaly the same as in the quick start - except I could not create thoth site into already existing folder.
Now goes exciting stuff - how to make this really work on heroku.
Getting it all to work
Since there isn't official 0.3.0 version of thoth we need to unpack it into vendor/gems folder of our heroku application first. Then config.ru has to be fixed so that version of thoth is used:
So require 'thoth' is basically replaced by the code to load all gems from vendor folder - got a bit of help from here.
Dir.glob(File.dirname(__FILE__) + "/vendor/gems/*").each do |path|
gem_name = File.basename(path.gsub(/-[\d\.]+$/, ''))
$LOAD_PATH << path + "/lib/"
require gem_name
end
#require 'thoth'
Now specify all required gems. You can read detailed instructions on installing gems on heroku or just create .gems file with following contents:
innate --version 2009.06.12
ramaze --version 2009.06.12
cssmin
jsmin
sanitize
Fix thoth.config file to use correct database connection:
db: <%= ENV['DATABASE_URL'] || ('sqlite:///'+ (Thoth::HOME_DIR) +'/db/live.db') %>
It's postgresql but it seems to be working for now. Another setting needs to be changed and that is url:
# Base URL of your site. This is necessary in order for Thoth to know how
# to construct links. Be sure to set this correctly or links may not work.
url: http://someappname.heroku.com/
Now everything is almost ready, the only thing left is database. You need to run thoth --migrate to crate ./db/live.db sqlite database. Then push it to heroku following instructions, basically one command - something like: heroku db:push sqlite://db/live.db
After this you can push the whole application to heroku and it should work.
Peace of cake, now you have your free personal blog in Ruby.
Due to some latest feedback and offers for translation I started looking at localizing JumpStart. That is something that I have been putting off for a long time. I guess I needed some reminding that localization is not something nice to have, it is really a must.
All is well, it's not really hard to localize an extension - well at least not technically, finding right phrases for translation is another story. But how to test this now? I completely switched to Linux at home so this short tip is for Linux users.
If you want to start your Firefox under a different locale from the one set at the system level you have to use command that goes something like this:
If your locale is in fact en_US :) and you want to test Serbian for example you could change your language like this:
I dug out this information from some old Ubuntu forum thread, hope you find it useful. If you have better way of doing this please let me know.
All is well, it's not really hard to localize an extension - well at least not technically, finding right phrases for translation is another story. But how to test this now? I completely switched to Linux at home so this short tip is for Linux users.
If you want to start your Firefox under a different locale from the one set at the system level you have to use command that goes something like this:
LANGUAGE=en_US LANG=en_US.UTF-8 firefox -no-remote -P "your_profile_name"(Firefox command line arguments)
If your locale is in fact en_US :) and you want to test Serbian for example you could change your language like this:
LANGUAGE=sr_RS LANG=sr_RS.UTF-8 firefox -no-remote -P "your_profile_name"You could even use language that is not installed on your machine, for example I don't have German locales installed but I can still use de_DE to test my extension:
LANGUAGE=de_DE LANG=de_DE.UTF-8 firefox -no-remote -P "your_profile_name"The Firefox obviously won't be shown in language you don't have installed on your machine but your extension will be showing it if you have it localized for the language.
I dug out this information from some old Ubuntu forum thread, hope you find it useful. If you have better way of doing this please let me know.
I have published XUL Schema on CodePlex. It is fairly complete and it should work correctly for most scenarios. Get the latest source code and follow instructions from the home page. Here are some screenshots.
All comments are welcome. If something is not working correctly please report and I'll surely look in to it.
Again, consider this work in progress, it should work correctly for most of the scenarios but there are scenarios where it will break - for example templates with HTML contents. While I'm developing my extensions I keep updating the schema so from time to time check out the latest version of the code.
All comments are welcome. If something is not working correctly please report and I'll surely look in to it.
Again, consider this work in progress, it should work correctly for most of the scenarios but there are scenarios where it will break - for example templates with HTML contents. While I'm developing my extensions I keep updating the schema so from time to time check out the latest version of the code.
Filtering Bookmarks by Tags in Your Extension
Mihailo Lalevic Monday March 30, 2009 @ 12:55 PM (PDT)
It is not possible to filter by multiple tags in bookmarks window in Firefox. So I thought to try to see how it can be done. This exercise is interesting too to see how templates work and how to change the query for template in runtime. I prepared a XUL window that is just enough to demonstrate the point.
First of all get to know Places, the heart of the Firefox's bookmarks and history management system. The Places database is where Firefox keeps all it's records on your bookmarks and history, and it is simply SQLite db/file. Here's the schema and the database itself can be found at Firefox's profiles folder, the file is named places.sqlite. You can view it using SQLite Database Browser.
With all the links out of the way lets look at the example file:
OK, lets quickly go through this. Lets skip the JavaScript part at the beginning, at the end there are two listbox elements that have templates. The first listbox is showing a list of your tags. It's very simple SQLite template. Datasource attribute defines the datasource on which the query will be executed. In this case the file is profile:places.sqlite, and that is Places database, other required attribute is querytype which is marking that our datasource is a SQLite file. We have very simple template that has only query and action elements. Query is just a SQLite query, simple, once you figure out what is where in the database. And template is using tag titles as labels in listitem. What it will do is just render a list of tags, and by selecting tags bookmarks will be filtered.
The second listbox is rendering all tagged bookmarks, that's just to show something until a tag is selected. The label is name of bookmarked page. It is pretty much the same thing as with tags listbox. It is going to be a bit different though, since the query is going to be changed dynamically.
So finally the JavaScript. doOnSelect function is doing all the work (well there's no other function there). On selection of tag, multiple can be selected, the function is just making a list of tag names separated by commas, updating the someSelectionQuery to include filter on tags. There is a little trick on group by and having - we're just making sure that particular place has the exact number of occurences as the number of tags selected. Basically all selected tags have to be parents of the bookmarked page, so that is what the query is checking. Oh, I forgot to mention Places SQL queries best practices.
At the end of the function we need to call builder.rebuild() on the templated element to update the content since the query is changed, it won't be updated by itself.
Phew, lots of work for such an ugly screen.
First of all get to know Places, the heart of the Firefox's bookmarks and history management system. The Places database is where Firefox keeps all it's records on your bookmarks and history, and it is simply SQLite db/file. Here's the schema and the database itself can be found at Firefox's profiles folder, the file is named places.sqlite. You can view it using SQLite Database Browser.
With all the links out of the way lets look at the example file:
<?xml version="1.0"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
title="Bookmarks - Test"
>
<script type="application/x-javascript">
var someSelectionQuery =
'select p.title as title ' +
'from moz_bookmarks_roots r ' +
'join moz_bookmarks tagsRoot on r.folder_id = tagsRoot.id ' +
'join moz_bookmarks tags on tagsRoot.id = tags.parent ' +
'join moz_bookmarks b on b.parent = tags.id ' +
'join moz_places p on b.fk = p.id ' +
"where r.root_name = 'tags' and tags.title in ({tags}) " +
'group by b.fk ' +
'having count(b.fk) = {count}';
function doOnSelect(tagList){
var items = tagList.selectedItems;
var count = tagList.selectedCount;
var query = document.getElementById('bookmarkslistQuery');
var tags = '';
var countStr = count + '';
for(var i=0; i < count; i++){
if(i != 0) tags += ',';
tags += "'" + tagList.selectedItems[i].label + "'";
}
var realQuery = someSelectionQuery.replace('{tags}', tags);
realQuery = realQuery.replace('{count}', countStr);
query.textContent = realQuery;
var ml = document.getElementById('mainList');
ml.builder.rebuild();
}
</script>
<listbox datasources="profile:places.sqlite" ref="*" querytype="storage" seltype="multiple" id="tagsList" onselect="doOnSelect(this);">
<template>
<query>
select tags.title
from moz_bookmarks_roots r
join moz_bookmarks tagsRoot on r.folder_id = tagsRoot.id
join moz_bookmarks tags on tagsRoot.id = tags.parent
where r.root_name = 'tags'
</query>
<action>
<listitem uri="?" label="?title"/>
</action>
</template>
</listbox>
<listbox datasources="profile:places.sqlite" ref="*" querytype="storage" id="mainList">
<template>
<query id="bookmarkslistQuery">
select b.title as title
from moz_bookmarks_roots r
join moz_bookmarks tagsRoot on r.folder_id = tagsRoot.id
join moz_bookmarks tags on tagsRoot.id = tags.parent
join moz_bookmarks b on b.parent = tags.id
</query>
<action id="blaction">
<listitem uri="?" label="?title"/>
</action>
</template>
</listbox>
</window>
OK, lets quickly go through this. Lets skip the JavaScript part at the beginning, at the end there are two listbox elements that have templates. The first listbox is showing a list of your tags. It's very simple SQLite template. Datasource attribute defines the datasource on which the query will be executed. In this case the file is profile:places.sqlite, and that is Places database, other required attribute is querytype which is marking that our datasource is a SQLite file. We have very simple template that has only query and action elements. Query is just a SQLite query, simple, once you figure out what is where in the database. And template is using tag titles as labels in listitem. What it will do is just render a list of tags, and by selecting tags bookmarks will be filtered.
The second listbox is rendering all tagged bookmarks, that's just to show something until a tag is selected. The label is name of bookmarked page. It is pretty much the same thing as with tags listbox. It is going to be a bit different though, since the query is going to be changed dynamically.
So finally the JavaScript. doOnSelect function is doing all the work (well there's no other function there). On selection of tag, multiple can be selected, the function is just making a list of tag names separated by commas, updating the someSelectionQuery to include filter on tags. There is a little trick on group by and having - we're just making sure that particular place has the exact number of occurences as the number of tags selected. Basically all selected tags have to be parents of the bookmarked page, so that is what the query is checking. Oh, I forgot to mention Places SQL queries best practices.
At the end of the function we need to call builder.rebuild() on the templated element to update the content since the query is changed, it won't be updated by itself.
Phew, lots of work for such an ugly screen.
After manually setting http handlers for a particular folder in IIS 5 and 6 and then seeing how it can be done programmatically we are ready to use it in our deployment.
It is quite simple actually. Here are the things we need to do:
1. Create web setup project
2. Create custom installer action (it's in VB though, but it is simple enough)
3. Override Commit method of the created installer class
4. Add your action to be executed in the commit phase of the setup
Steps 1 and 2 should be straight forward, however steps 3 and 4 require some more explanation. First of all the web setup project exposes two useful properties through Installation Address User Interface Dialog Box (that's just where you select your site and virtual folder): TARGETSITE and TARGETVDIR. These are as their names suggest: site (its metabase value) and virtual folder where the deployment will occur. That simplifies our life in a way that we can get a reference to our virtual folder's metabase entry like this:
Piece of cake right?
Now, what have we done is get TARGETSITE parameter, and we took just the site's id (because the format doesn't exactly fit), we used TARGETVDIR and composed the path we can use in DirectoryEntry constructor. After getting the directory entry you just do your configuration magic.
There is one piece of the puzzle missing - how do we get those context parameters into our custom installer action? As the documentation says the parameters are available, however we still need to pass them into our action as part of the custom action data. Nothing easier:

Or in plain text: /TARGETVDIR="[TARGETVDIR]" /TARGETSITE="[TARGETSITE]"
And at the end, the answer to Why do we do this in the commit phase? Because the web setup will overwrite anything you change before the commit phase. It is creating the virtual folder, or setting default configuration to it if it already exists, in the commit phase. This means that not before the commit phase that you have the correct starting point for your changes.
So to conclude: nothing ground breaking, just lots of simple little steps that you cannot really quickly figure out from confusing MSDN; unless, of course you are making your living out of deployment projects and you knew all this already.
It is quite simple actually. Here are the things we need to do:
1. Create web setup project
2. Create custom installer action (it's in VB though, but it is simple enough)
3. Override Commit method of the created installer class
4. Add your action to be executed in the commit phase of the setup
Steps 1 and 2 should be straight forward, however steps 3 and 4 require some more explanation. First of all the web setup project exposes two useful properties through Installation Address User Interface Dialog Box (that's just where you select your site and virtual folder): TARGETSITE and TARGETVDIR. These are as their names suggest: site (its metabase value) and virtual folder where the deployment will occur. That simplifies our life in a way that we can get a reference to our virtual folder's metabase entry like this:
webSiteId = Context.Parameters["TARGETSITE"];
webSiteId = webSiteId.Substring(webSiteId.LastIndexOf('/') + 1);
virtualDirectory = Context.Parameters["TARGETVDIR"];
var myVirtualDir = new System.DirectoryServices.DirectoryEntry(
"IIS://localhost/W3SVC/" + webSiteId +"/ROOT/" + virtualDirectory);
Piece of cake right?
Now, what have we done is get TARGETSITE parameter, and we took just the site's id (because the format doesn't exactly fit), we used TARGETVDIR and composed the path we can use in DirectoryEntry constructor. After getting the directory entry you just do your configuration magic.
There is one piece of the puzzle missing - how do we get those context parameters into our custom installer action? As the documentation says the parameters are available, however we still need to pass them into our action as part of the custom action data. Nothing easier:
Or in plain text: /TARGETVDIR="[TARGETVDIR]" /TARGETSITE="[TARGETSITE]"
And at the end, the answer to Why do we do this in the commit phase? Because the web setup will overwrite anything you change before the commit phase. It is creating the virtual folder, or setting default configuration to it if it already exists, in the commit phase. This means that not before the commit phase that you have the correct starting point for your changes.
So to conclude: nothing ground breaking, just lots of simple little steps that you cannot really quickly figure out from confusing MSDN; unless, of course you are making your living out of deployment projects and you knew all this already.
When I was setting http handlers for a particular folder in IIS 5 and 6 one of the requirements was to do it programmatically. Using System.DirectoryServices.DirectoryEntry seems to be the easiest way to do it.
Getting access to your IIS configuration is simple:
new System.DirectoryServices.DirectoryEntry("IIS://localhost/W3SVC")
That's it. This will give you access to the sites folder or your IIS. You would need to go through children nodes and find your site, and then through its children all they way down to the virtual folder you want to setup. Now if you know exactly which site you want to setup you could access it by simply using full path, like this:
new System.DirectoryServices.DirectoryEntry("IIS://localhost/W3SVC/1/ROOT/MyTestSite")
If you have more then one web site and more then one virtual folder to deal with things are not that simple anymore. But it's not too complex either. IIS 6.0 Resource Toolkit is your friend here. Whatever you see in Metabase explorer you can find/change programmatically. For example to get the list of all web sites on your local IIS you could do the following:
var iis = new System.DirectoryServices.DirectoryEntry("IIS://localhost/W3SVC");
var sites = (from DirectoryEntry entry in iis.Children
where entry.SchemaClassName == "IIsWebServer"
select entry).ToList();
This will list you all web sites you have on your IIS. The root folder is normally imediatelly beneath website, you can get it like this (in this example from the first web site):
var root = (from DirectoryEntry entry in sites[0].Children
where entry.Name == "ROOT"
select entry).FirstOrDefault();
And now find a virtual folder you are looking for:
var virtualFolder
= (from DirectoryEntry entry in root.Children
where entry.Name == "MyTestSite"
select entry).FirstOrDefault();
So the pattern is clear, we go through children and we are finding what we want. Editing settings is pretty easy, if you want to create a virtual folder all you need to do is add a child to the root folder, or some other virtual folder:
root.Children.Add("AnotherVirtualFolder", "IIsWebVirtualDir");
root.CommitChanges();
You need to call CommitChanges method to, errr ..., commit changes you've just made, otherwise they won't be applied. Or you can add custom web folder:
var myTargetFolder = virtualFolder.Children.Add("Scripts", "IIsWebDirectory");
virtualFolder.CommitChanges();
And now you can change properties on your folder, or on anything else really:
myTargetFolder.Properties["ScriptMaps"].Clear();
myTargetFolder.Properties["ScriptMaps"].Add(@".js,c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll,1");
myTargetFolder.CommitChanges();
Again take a peek in your metabase explorer to see what you can change. In this case ScriptMaps is an array so if we want to handle only *.js files in our folder we clear all entries and then add just the one we are interested in.
Well it's pretty simple, now you can do whatever you want with your IIS. Interestingly, if you want to manipulate the Metabase during installation things might be even simpler, however there are couple of cavets along the way. More on that soon.
Getting access to your IIS configuration is simple:
new System.DirectoryServices.DirectoryEntry("IIS://localhost/W3SVC")
That's it. This will give you access to the sites folder or your IIS. You would need to go through children nodes and find your site, and then through its children all they way down to the virtual folder you want to setup. Now if you know exactly which site you want to setup you could access it by simply using full path, like this:
new System.DirectoryServices.DirectoryEntry("IIS://localhost/W3SVC/1/ROOT/MyTestSite")
If you have more then one web site and more then one virtual folder to deal with things are not that simple anymore. But it's not too complex either. IIS 6.0 Resource Toolkit is your friend here. Whatever you see in Metabase explorer you can find/change programmatically. For example to get the list of all web sites on your local IIS you could do the following:
var iis = new System.DirectoryServices.DirectoryEntry("IIS://localhost/W3SVC");
var sites = (from DirectoryEntry entry in iis.Children
where entry.SchemaClassName == "IIsWebServer"
select entry).ToList();
This will list you all web sites you have on your IIS. The root folder is normally imediatelly beneath website, you can get it like this (in this example from the first web site):
var root = (from DirectoryEntry entry in sites[0].Children
where entry.Name == "ROOT"
select entry).FirstOrDefault();
And now find a virtual folder you are looking for:
var virtualFolder
= (from DirectoryEntry entry in root.Children
where entry.Name == "MyTestSite"
select entry).FirstOrDefault();
So the pattern is clear, we go through children and we are finding what we want. Editing settings is pretty easy, if you want to create a virtual folder all you need to do is add a child to the root folder, or some other virtual folder:
root.Children.Add("AnotherVirtualFolder", "IIsWebVirtualDir");
root.CommitChanges();
You need to call CommitChanges method to, errr ..., commit changes you've just made, otherwise they won't be applied. Or you can add custom web folder:
var myTargetFolder = virtualFolder.Children.Add("Scripts", "IIsWebDirectory");
virtualFolder.CommitChanges();
And now you can change properties on your folder, or on anything else really:
myTargetFolder.Properties["ScriptMaps"].Clear();
myTargetFolder.Properties["ScriptMaps"].Add(@".js,c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll,1");
myTargetFolder.CommitChanges();
Again take a peek in your metabase explorer to see what you can change. In this case ScriptMaps is an array so if we want to handle only *.js files in our folder we clear all entries and then add just the one we are interested in.
Well it's pretty simple, now you can do whatever you want with your IIS. Interestingly, if you want to manipulate the Metabase during installation things might be even simpler, however there are couple of cavets along the way. More on that soon.
Setup Http Handler For a Particular Folder in IIS 5 and 6
Mihailo Lalevic Monday January 19, 2009 @ 02:34 PM (PST)
The other day I was setting up my custom ASP.Net http handler in IIS 7. Easy and painless. Using IIS manager just go to the folder you like and configure it, a snap. I tried to do the same thing in IIS 5.1 (the same thing with IIS 6), but no such luck. If you want to do it in a virtual folder, then that's not a problem - it's easy to set it up. However I wanted to set it up on a particular subfolder - no luck, IIS manager does not give you that option.
I was handling .js files so setting the handler on the top folder was a bit of an inconvenience. Luckily it is just a limitation of the IIS manager, not the IIS itself. What you need is to get yourself Metabase explorer which is a part of the IIS 6.0 Resource Toolkit and do a simple surgery.
Here is what I did:
I added folders beneath my virtual directory - Test in this case (Scripts and Dynamic), and added ScriptMaps key:
Normally it would inherit ScriptMaps from Test folder something like this:
I want it to handle only .js files so I added the key ScriptMaps (since it was inherited from the virtual directory it was not showing up in the list of keys):
And added a value for my files:
or in plain text that is:
.js,c:\windows\microsoft.net\framework\v2.0.50725\aspnet_isapi.dll,1
note the . (dot) at the beginning and the path to the ASP.Net isapi filter might be different on your machine.
And that's it, I am only handling files I want to be handled by me in this folder, I can setup other file types if I wish in future. You still need to register your http handler, slight variation to the explanation is to put Scripts\Dynamic\*.js (in this case) for path attribute value.
I will add post on how to set this programatically soon.
I was handling .js files so setting the handler on the top folder was a bit of an inconvenience. Luckily it is just a limitation of the IIS manager, not the IIS itself. What you need is to get yourself Metabase explorer which is a part of the IIS 6.0 Resource Toolkit and do a simple surgery.
Here is what I did:
I added folders beneath my virtual directory - Test in this case (Scripts and Dynamic), and added ScriptMaps key:
Normally it would inherit ScriptMaps from Test folder something like this:
I want it to handle only .js files so I added the key ScriptMaps (since it was inherited from the virtual directory it was not showing up in the list of keys):
And added a value for my files:
or in plain text that is:.js,c:\windows\microsoft.net\framework\v2.0.50725\aspnet_isapi.dll,1
note the . (dot) at the beginning and the path to the ASP.Net isapi filter might be different on your machine.
And that's it, I am only handling files I want to be handled by me in this folder, I can setup other file types if I wish in future. You still need to register your http handler, slight variation to the explanation is to put Scripts\Dynamic\*.js (in this case) for path attribute value.
I will add post on how to set this programatically soon.
Ajax.NET: Disable buttons until postback finishes
Mihailo Lalevic Saturday August 30, 2008 @ 01:46 PM (PDT)
When developing Web Forms in ASP.NET it is usually the case that we have multiple postbacks on a page. When there are Ajax calls as well it can easily happen that we can have multiple outstanding postbacks - e.g. postback by dropdown list immediately followed by a button click, or simply multiple button clicks. Due to various reasons those calls can end up in different sequence on the server (e.g. network latency). For some we might not care, but for some the sequence might be important.
What I'm showing here is a simple client solution to the problem. It will simply disable buttons while the postback ends thus preventing user to click on them until the postback had finished.
This is fairly simple code, without comments it would be really short. What it does is subscribing to page submit and load events and is disabling and enabling buttons respectively. Just put it somewhere on a part of the page that will be loaded first time the page loads.
You can make this more complicated if you need to do something specific depending on which element caused the postback by using different signature for onSubmit function. Here is documentation for the beginRequest event. Basically it will accept sender and args and you can use args.get_postBackElement() for example and make decisions what to do with your page elements then - hide them, disable them, animate them, whatever.
And at the end, remember that despite all the effort done on the client side you will always have to handle any eventuality on the server. Always remember, any client input is evil and it has to be validated - in this case postback sequence.
What I'm showing here is a simple client solution to the problem. It will simply disable buttons while the postback ends thus preventing user to click on them until the postback had finished.
<script language="javascript" type="text/javascript">
//on the page submit we want to disable buttons until the call is finished
// and then reenable them
(function() {
//add on the page load event that will register our scripts
//for all significant events
Sys.Application.add_load(setupButtonDisablers);
function setupButtonDisablers() {
//subscribe to on page load and submit events
//on page load we will enable buttons
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(onPageLoad);
//on page submit we will disable them
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(onSubmit);
//remove setup code so it will never be called again
Sys.Application.remove_load(setupButtonDisablers);
}
//on page load - enable all the relevant buttons
function onPageLoad() {
findAndEnable('<%= MyButton1.ClientId %>');
findAndEnable('<%= MyButton2.ClientId %>');
}
//on page submit - disable all the relevant buttons
function onSubmit() {
findAndDisable('<%= MyButton1.ClientId %>');
findAndDisable('<%= MyButton2.ClientId %>');
}
function findAndDisable(id) {
findAndSetDisabledProperty(id, true);
}
function findAndEnable(id) {
findAndSetDisabledProperty(id, false);
}
//finds and sets disabled property of a searched control
function findAndSetDisabledProperty(id, value) {
var control = $get(id);
if (control) {
control.disabled = value;
}
}
})();
</script>
This is fairly simple code, without comments it would be really short. What it does is subscribing to page submit and load events and is disabling and enabling buttons respectively. Just put it somewhere on a part of the page that will be loaded first time the page loads.
You can make this more complicated if you need to do something specific depending on which element caused the postback by using different signature for onSubmit function. Here is documentation for the beginRequest event. Basically it will accept sender and args and you can use args.get_postBackElement() for example and make decisions what to do with your page elements then - hide them, disable them, animate them, whatever.
And at the end, remember that despite all the effort done on the client side you will always have to handle any eventuality on the server. Always remember, any client input is evil and it has to be validated - in this case postback sequence.