Wednesday, November 29, 2006

self-signing certs in iis 6

Easiest way to do this is to download the IIS 6 Resource Kit Tools. Then find the site's id that will be assigned the cert. Search for the site's name in %SystemRoot%\System32\Inetsrv\MetaBase.xml, the id is the number appended in the Location attribute. For example:

<IIsWebServer Location="/LM/W3SVC/445577612" AuthFlags="0"
LogPluginClsid="{FF160663-DE82-11CF-BC0A-00AA006111E0}" SecureBindings=":443:"
ServerAutoStart="FALSE" ServerBindings=":80: 192.168.88.62:80:" ServerComment="testsite" />

The id here is 445577612.

Then, the command to assign the self-signed cert is:

C:\Program Files\IIS Resources\SelfSSL>selfssl.exe /N:CN=SERV2003DEV /K:1024 /V:700 /S:445577612 /P:443

Where CN is the server's name, K is the key length, V is the number of days the cert is valid, S is the site id, P is the port.

I did this on Windows 2003 Server, so no idea if it works in XP.

Tuesday, November 28, 2006

loading a cert into IIS 6 w/o a pending request

Thank you TechNet:
http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/53dfdb5e-6106-4d99-85bb-da199bc27c7e.mspx?mfr=true

Basically all that is needed is:

certutil -addstore my certnew.cer

And then it'll appear in the "Assign an Existing Certificate" wizard selection and be available for selection.

Wednesday, November 15, 2006

ActiveRecord in .Net

I'm using ActiveRecord in .Net for a school project. And it's making db interaction somewhat bearable. Coming from a Hibernate/ActiveRecord background, this is a breath of fresh air. Never been a fan of the data-mapper/set and stored proc that MS is so up on. Thanks to the Castle (http://castleproject.org/) guys for putting this together, it's very simple to get up and running and I found it _far_ easier to understand their tutorial than any of the NHibernate ones. Their blog app is a piece of cake to understand and runs out of the box (granted you have have a "test" db created).

The biggest issue I had was connecting to SQLServer Express 2005. Here's the connection string I ended up using:

Server=127.0.0.1,1433;Database=patstracks;Integrated Security=SSPI


ActiveRecord really makes it easy to decorate POCOs using attributes:

[ActiveRecord("[Client]")]

public class Client : ActiveRecordBase{
...
[PrimaryKey]

public int Id

{

get { return id; }

set { id = value; }



}
...
public static Client[] FindByNameLike(string name)

{

return (Client[])Client.FindAll(typeof(Client), new Order[] {Order.Asc("Name") }, new ICriterion[] { Expression.Like("Name", name+"%")});



}
...
}

Wednesday, November 01, 2006

in place phone editor via Ajax

UPDATE: I went about this the wrong way. Should've just overridden the necessary methods. I'll do it and replace this when I'm done.

Morphed the InPlaceEditor and made it more friendly for handling phone number entry:


// script.aculo.us controls.js v1.6.4, Wed Sep 06 11:30:58 CEST 2006

// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
// (c) 2005 Jon Tirsen (http://www.tirsen.com)
// Contributors:
// Richard Livsey
// Rahul Bhargava
// Rob Wills
//
// See scriptaculous.js for full license.
/*
*Only tested via load_text url
*Parses for extension on '$'
*Returns input as phone_value and ext_value
*/
Ajax.InPlacePhoneEditor = Class.create();
Ajax.InPlacePhoneEditor.defaultHighlightColor = "#FFFF99";
Ajax.InPlacePhoneEditor.prototype = {
initialize: function(element, url, options) {
this.url = url;
this.element = $(element);

this.options = Object.extend({
okButton: true,
okText: "ok",
cancelLink: true,
cancelText: "cancel",
savingText: "Saving...",
clickToEditText: "Click to edit",
okText: "ok",
rows: 1,
onComplete: function(transport, element) {
new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
},
onFailure: function(transport) {
alert("Error communicating with the server: " + transport.responseText.stripTags());
},
callback: function(form) {
return Form.serialize(form);
},
handleLineBreaks: true,
loadingText: 'Loading...',
savingClassName: 'inplaceeditor-saving',
loadingClassName: 'inplaceeditor-loading',
formClassName: 'inplaceeditor-form',
highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
highlightendcolor: "#FFFFFF",
externalControl: null,
submitOnBlur: false,
ajaxOptions: {},
evalScripts: false
}, options || {});

if(!this.options.formId && this.element.id) {
this.options.formId = this.element.id + "-inplaceeditor";
if ($(this.options.formId)) {
// there's already a form with that name, don't specify an id
this.options.formId = null;
}
}

if (this.options.externalControl) {
this.options.externalControl = $(this.options.externalControl);
}

this.originalBackground = Element.getStyle(this.element, 'background-color');
if (!this.originalBackground) {
this.originalBackground = "transparent";
}

this.element.title = this.options.clickToEditText;

this.onclickListener = this.enterEditMode.bindAsEventListener(this);
this.mouseoverListener = this.enterHover.bindAsEventListener(this);
this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
Event.observe(this.element, 'click', this.onclickListener);
Event.observe(this.element, 'mouseover', this.mouseoverListener);
Event.observe(this.element, 'mouseout', this.mouseoutListener);
if (this.options.externalControl) {
Event.observe(this.options.externalControl, 'click', this.onclickListener);
Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
}
},
enterEditMode: function(evt) {
if (this.saving) return;
if (this.editing) return;
this.editing = true;
this.onEnterEditMode();
if (this.options.externalControl) {
Element.hide(this.options.externalControl);
}
Element.hide(this.element);
this.createForm();
this.element.parentNode.insertBefore(this.form, this.element);
if (!this.options.loadTextURL){
Field.scrollFreeActivate(this.editField);
}
// stop the event to avoid a page refresh in Safari
if (evt) {
Event.stop(evt);
}
return false;
},
createForm: function() {
this.form = document.createElement("form");
this.form.id = this.options.formId;
Element.addClassName(this.form, this.options.formClassName)
this.form.onsubmit = this.onSubmit.bind(this);

this.createEditField();

if (this.options.textarea) {
var br = document.createElement("br");
this.form.appendChild(br);
}

if (this.options.okButton) {
okButton = document.createElement("input");
okButton.type = "submit";
okButton.value = this.options.okText;
okButton.className = 'editor_ok_button';
this.form.appendChild(okButton);
}

if (this.options.cancelLink) {
cancelLink = document.createElement("a");
cancelLink.href = "#";
cancelLink.appendChild(document.createTextNode(this.options.cancelText));
cancelLink.onclick = this.onclickCancel.bind(this);
cancelLink.className = 'editor_cancel';
this.form.appendChild(cancelLink);
}
},
hasHTMLLineBreaks: function(string) {
if (!this.options.handleLineBreaks) return false;
return string.match(/<br/i) || string.match(/<p>/i);
},
convertHTMLLineBreaks: function(string) {
return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
},
createEditField: function() {
var text;
if(this.options.loadTextURL) {
text = this.options.loadingText;
} else {
text = this.getText();
}

var obj = this;

if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
this.options.textarea = false;
var textField = document.createElement("input");
textField.obj = this;
textField.type = "text";
textField.name = "phone_value";
textField.value = text;
textField.style.backgroundColor = this.options.highlightcolor;
textField.className = 'editor_field';

var size = 20;
if (size != 0) textField.size = size;
if (this.options.submitOnBlur)
textField.onblur = this.onSubmit.bind(this);
textField.maxLength = size;
this.editField_phone = textField;

var textField = document.createElement("input");
textField.obj = this;
textField.type = "text";
textField.name = "ext_value";
textField.value = text;
textField.style.backgroundColor = this.options.highlightcolor;
textField.className = 'editor_field';
var size = 6;
if (size != 0) textField.size = size;
if (this.options.submitOnBlur)
textField.onblur = this.onSubmit.bind(this);
textField.maxLength = size;
this.editField_ext = textField;
}

if(this.options.loadTextURL) {
this.loadExternalText();
}


this.form.appendChild(this.editField_phone);
this.form.appendChild(document.createTextNode(" ext."));
this.form.appendChild(this.editField_ext);
},
getText: function() {
return this.element.innerHTML;
},
loadExternalText: function() {
Element.addClassName(this.form, this.options.loadingClassName);
this.editField_phone.disabled = true;
this.editField_ext.disabled = true;

new Ajax.Request(
this.options.loadTextURL,
Object.extend({
asynchronous: true,
onComplete: this.onLoadedExternalText.bind(this)
}, this.options.ajaxOptions)
);
},
onLoadedExternalText: function(transport) {
Element.removeClassName(this.form, this.options.loadingClassName);
this.editField_phone.disabled = false;
this.editField_ext.disabled = false;

var load_values = transport.responseText.stripTags().split("$");
if((load_values.length == 1) || (load_values.length == 2)){
this.editField_phone.value = load_values[0];
if(load_values.length == 2 ){
this.editField_ext.value = load_values[1]
}
}
Field.scrollFreeActivate(this.editField_phone);
Field.scrollFreeActivate(this.editField_ext);
},
onclickCancel: function() {
this.onComplete();
this.leaveEditMode();
return false;
},
onFailure: function(transport) {
this.options.onFailure(transport);
if (this.oldInnerHTML) {
this.element.innerHTML = this.oldInnerHTML;
this.oldInnerHTML = null;
}
return false;
},
onSubmit: function() {
// onLoading resets these so we need to save them away for the Ajax call
var form = this.form;
var value = this.editField_phone.value + "$" + this.editField_ext.value;

// do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
// which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
// to be displayed indefinitely
this.onLoading();

if (this.options.evalScripts) {
new Ajax.Request(
this.url, Object.extend({
parameters: this.options.callback(form, value),
onComplete: this.onComplete.bind(this),
onFailure: this.onFailure.bind(this),
asynchronous:true,
evalScripts:true
}, this.options.ajaxOptions));
} else {
new Ajax.Updater(
{ success: this.element,
// don't update on failure (this could be an option)
failure: null },
this.url, Object.extend({
parameters: this.options.callback(form, value),
onComplete: this.onComplete.bind(this),
onFailure: this.onFailure.bind(this)
}, this.options.ajaxOptions));
}
// stop the event to avoid a page refresh in Safari
if (arguments.length > 1) {
Event.stop(arguments[0]);
}
return false;
},
onLoading: function() {
this.saving = true;
this.removeForm();
this.leaveHover();
this.showSaving();
},
showSaving: function() {
this.oldInnerHTML = this.element.innerHTML;
this.element.innerHTML = this.options.savingText;
Element.addClassName(this.element, this.options.savingClassName);
this.element.style.backgroundColor = this.originalBackground;
Element.show(this.element);
},
removeForm: function() {
if(this.form) {
if (this.form.parentNode) Element.remove(this.form);
this.form = null;
}
},
enterHover: function() {
if (this.saving) return;
this.element.style.backgroundColor = this.options.highlightcolor;
if (this.effect) {
this.effect.cancel();
}
Element.addClassName(this.element, this.options.hoverClassName)
},
leaveHover: function() {
if (this.options.backgroundColor) {
this.element.style.backgroundColor = this.oldBackground;
}
Element.removeClassName(this.element, this.options.hoverClassName)
if (this.saving) return;
this.effect = new Effect.Highlight(this.element, {
startcolor: this.options.highlightcolor,
endcolor: this.options.highlightendcolor,
restorecolor: this.originalBackground
});
},
leaveEditMode: function() {
Element.removeClassName(this.element, this.options.savingClassName);
this.removeForm();
this.leaveHover();
this.element.style.backgroundColor = this.originalBackground;
Element.show(this.element);
if (this.options.externalControl) {
Element.show(this.options.externalControl);
}
this.editing = false;
this.saving = false;
this.oldInnerHTML = null;
this.onLeaveEditMode();
},
onComplete: function(transport) {
this.leaveEditMode();
this.options.onComplete.bind(this)(transport, this.element);
},
onEnterEditMode: function() {},
onLeaveEditMode: function() {},
dispose: function() {
if (this.oldInnerHTML) {
this.element.innerHTML = this.oldInnerHTML;
}
this.leaveEditMode();
Event.stopObserving(this.element, 'click', this.onclickListener);
Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
if (this.options.externalControl) {
Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
}
}
};


Ajax.InPlacePhoneEditor.prototype.__initialize = Ajax.InPlaceEditor.prototype.initialize;
Ajax.InPlacePhoneEditor.prototype.__getText = Ajax.InPlaceEditor.prototype.getText;
Ajax.InPlacePhoneEditor.prototype.__onComplete = Ajax.InPlaceEditor.prototype.onComplete;
Ajax.InPlacePhoneEditor.prototype = Object.extend(Ajax.InPlaceEditor.prototype, {

initialize: function(element, url, options){
this.__initialize(element,url,options)
this.setOptions(options);
this._checkEmpty();
},

setOptions: function(options){
this.options = Object.extend(Object.extend(this.options,{
emptyText: 'click to edit...',
emptyClassName: 'inplaceeditor-empty'
}),options||{});
},

_checkEmpty: function(){
if( this.element.innerHTML.length == 0 ){
this.element.appendChild(
Builder.node('span',{className:this.options.emptyClassName},this.options.emptyText));
}
},

getText: function(){
document.getElementsByClassName(this.options.emptyClassName,this.element).each(function(child){
this.element.removeChild(child);
}.bind(this));
return this.__getText();
},

onComplete: function(transport){
this._checkEmpty();
this.__onComplete(transport);
}
});