2009年11月15日日曜日

[IIS6.0] Webガーデン

IIS6.0導入されたWebガーデンについてのメモです。

Webガーデンで最大ワーカープロセス数を2以上にした場合に注意が必要。
Webガーデンとは、1つのアプリケーションを複数のワーカープロセスで動かす仕組み。
アプリケーション変数や、セッションは共有されない。
つまり、SessionIdは別物になる。
Session領域も別物になる。
システム構築時にクラスタ構成と同じように考慮する必要がある。

あんな簡単に設定できるものが、こんなに大きく影響があってよいのですかねぇ。

2009年11月11日水曜日

[ASP.NET MVC] リストのモデルバインド

ASP.NET MVCでモデルバインドが便利っぽいような不便っぽいような。
新規にリストの値をバインドするなら問題ないのですよ。

Model

Public Class PrivateInfo
Public Name As String
Public History As List(Of History)
End Class

Public Class History
Public eventDate As DateTime
Public Score As Int32
Public Cost As Int32
End Class


View

<%
For each item In Model.History
Dim index As Integer = Model.History.IndexOf(item)
%>
<%=Html.TextBox(String.Format("History[{0}].Score", index), item.Score)%>
<%=Html.TextBox(String.Format("History[{0}].Cost", index), item.Cost)%>

<% Next%>


ところがですね、すでにある程度の値が入っているリストに画面でeventDateを設定させようとしてUpdateModelすると、ScoreとCostが消えちゃうのです。
View

<%
For each item In Model.History
Dim index As Integer = Model.History.IndexOf(item)
%>
<%=Html.TextBox(String.Format("History[{0}].eventDate", index), item.eventDate)%>

<% Next%>


Controller

<AcceptVerbs(HttpVerbs.Post)> _
Public Function Input2(ByVal collection As FormCollection) As ActionResult
Dim model As Models.PrivateInfo = Session("PrivateInfo")

UpdateModel(model)

Return View(model)
End Function



そこまでやってくれないんですね。
対策としては、その他の項目もPostしちゃうと。

View

<%
For each item In Model.History
Dim index As Integer = Model.History.IndexOf(item)
%>
<%=Html.TextBox(String.Format("History[{0}].eventDate", index), item.eventDate)%>
<%=Html.Hidden(String.Format("History[{0}].Score", index), item.Score)%>
<%=Html.Hidden(String.Format("History[{0}].Cost", index), item.Cost)%>

<% Next%>



イケテナイ。
自分でマージするか

2009年10月20日火曜日

[C#] int?

知りませんでした。

int?

これがなんなのかを調べるのにも苦労しちゃいました。
検索エンジンで「?」なんて入れても引っかからないし。。。

ま、素直にMSDNを調べればわかったことなんですけどね。

Null値許容のint型って事なんですね。
.Net Framework 2.0の時点であったとは。。。

ちなにみVBだと

Dim i As Nullable(Of Int32)

って書くらしいです。

2009年9月10日木曜日

[IIS]IISで指定の拡張子のファイルをクライアントに見せなくする

たとえば、xmlファイルを公開フォルダ内においていた場合、
デフォルトの設定だとクライアントから要求があれば見えてしまいます。
それを見えなくする方法があります。これはIIS6.0以上のバージョンの場合です。

まず、IISを止めて%SystemRoot%\system32\inetsrv\MetaBase.xmlを開きます。
その中の<IISMimeMap>タグを見てください。

<IISMimeMap Location = "/LM/MimeMap"
MimeMap=".asx,vide/x-ms-asf
.xml,text/xml
.tsv,text/tab-separated-values
(略)
">
</IIsMimeMap>

なんて感じになっていると思います。
これの「.xml,text/xml」行を消しちゃいます。

これでOKです。

ブラウザからxmlファイルにアクセスすると 404エラーが返されると思います。
また、これは仮想ディレクトリ単位では出来ず、サイト単位でしかできないようです。


ついでにIIS5.1(XP Proとか)の場合なんですが、MetaBase.xmlが無くて、MetaBase.binというバイナリに
設定情報が書かれています。その為、直接の編集は出来ず、編集方法が良くわかりませんでした。

ですが、URLScanってツールを使うと実現できます。
これをダウンロード、インストールすると%SystemRoot%\system32\inetsrv\URLScanってフォルダに展開されています。
このファイルのURLScan.iniに見せたくないファイルの拡張子を指定することが出来ます。

Optionsセクションで、UseAllowExtensionsの値が0だとDenyExtensionsが有効、値が1だとAllowExtensionsが有効と言うこと。

[AllowExtensions] --- 見せるファイル
[DenyExtensions] --- 見せないファイル

ここのDenyExtensionsセクションに「.xml」を足してやるとクライアントから要求されても送信しない
です。

もしくはUseAllowExtensionsを1にして、見せる拡張子をひたすら書くと。
このほうが安心ですかね。メンドクサイけど。

で、こいつはIIS6でも動くみたいですね。

2009年9月2日水曜日

[.Net] .NetでのCOM相互運用

.Netで作成したDLLをCOM(ActiveX?)としても使うようにするためのメモ

まずはクラスライブラリとしてプロジェクトを作成します。
プロジェクトのプロパティでアプリケーションタブ内のアセンブリ情報から「アセンブリをCOM参照可能にする」にチェックを入れます。
あとは、コンパイルタブの「COM相互運用機能の登録」にもチェックを入れておくと、デバッグとかが楽かも。
プロジェクトにクラスを足すときは、「COMクラス」を使うのがお勧めです。

次に、COMの確認。
VBSファイルを作ってやるとか、VB6を使うとか、CraeteObjectで呼んでみるとかがありますね。

Dim obj
Set obj = CreateObject("ClassLibrary1.ComClass1")
MsgBox o.MethodTest()

こんな感じですかね。

後は、VSの入っていない環境にCOMを設定する方法。
WinXPとFramework 2.0の場合で具体例で書きます。
コマンドプロンプトで「C:\WINDOWS\Microsoft.Net\Framework\v2.0.50727」に移動します。
でコマンド「regasm [DLLの絶対パス] /tlb /codebase」を実行します。
ワーニングが出ますが成功って感じです。

このコマンド、「/codebase」をつけないとうまくいかないんですよね。
/codebaseをつけないと、登録しただけではうまく動かなくて、/unregisterするとうまくいって。。。
色々やりすぎて原因不明です。このまま迷宮に入れておきます。

メソッドの修正とかしてもモジュールを上書きするだけでOKです。
(クラスの追加、削除は再登録がいるかも?)
これがアセンブリの著名をつけない時のメリットですね。
アセンブリの著名をつけちゃうと、GACに登録はされますが、
バージョン管理をきっちりやる必要が出てきます。
ちょっとやってみたんですけど、バージョンダウンして動かすことが出来ませんでした。
これはそのうち解決したいです。

以下はその他の気になった点のメモです。
・Object型をCOM公開すると警告(BC42102)が出るが問題なし
  →プロジェクトファイルに以下の文を追加で出なくなる
+Project
 +PropertyGroup
  <NoWarn>42102</NoWarn>

・オーバーロードと可変引数は使えない
・自作クラスを継承したクラスがうまく公開できない(たぶん個人的な知識不足が原因)

・・・いつか、この記事をまとめなおそう。。。

2009年2月4日水曜日

[C#]週番号の取得

VB6で言う所のDatePart(DateInterval.WeekOfYear, Now)をC#でやると。。。


Calendar cal = CultureInfo.CurrentCulture.Calendar;
CalendarWeekRule cwr = CultureInfo.CurrentCulture.DateTimeFormat.CalendarWeekRule;
DayOfWeek firstDay = DayOfWeek.Monday;

int weekNumber = cal.GetWeekOfYear(Target, cwr, firstDay);


こんな感じで取れました。
firstDayのあたりはお好みで。

2009年1月27日火曜日

[WPF]SliderとTextBoxのバインド

XAML側でのバインド方法はすぐわかったんですけど、ビジネスロジック側でバインドする方法がなかなか見つからなかった。。。

【XAMLでやるとき】







【C#でやるとき】

Binding db = new Binding();
db.ElementName = "Slider1";
db.Path = new PropertyPath("Value");
this.TextBox1.SetBinding(TextBox.TextProperty, db);

2009年1月23日金曜日

[WPF]画像をピクセル等倍で表示する

WPFの特徴として表示するコントロール等のサイズを実行環境に合わせて調整する機能があるようです。
参考「WPF アプリケーションのピクセル スナップ

でも、これ、困るんです。
JPG画像を表示したときに勝手に拡大されたり縮小されちゃってぼやけた感じになるのです。(なったのです。)

画像は600*400で72dpiの画像(dpiは関係ない?)で、これを最大化したフォームの中央にピクセル等倍で表示したかったのですが、普通のWindowsFormのやり方では800*533.333...で表示されちゃいます。
これをオリジナルのサイズで表示するにはこうやると良いっぽい。

【XAML】


 


【C#】

BitmapImage bi= new BitmapImage(new Uri("C:\test.jpg"));
this.ImageArea.Source = bi;
BitmapSource SourceData = (BitmapSource)this.ImageArea.Source;
this.ImageArea.Width = SourceData.PixelWidth;
this.ImageArea.Height= SourceData.PixelHeight;

[C#]配列のソート(例えばFileInfo)

FileInfoクラスの更新時間順にソートしたい!なんて時のやり方。


private FileInfo[] GetFiles
{
FileInfo[] fis;
//・・・(略)
Array.Sort(fis, delegate(FileInfo x, FileInfo y) { return x.LastWriteTime.CompareTo(y.LastWriteTime); });
}


あんまりC#の構文に詳しくないのですが、こんなのがメソッドの中に書けるんですね。
イケてるインデントの取り方がわかりません。
こうかな?

Array.Sort(
  fis
  ,
  delegate(FileInfo x, FileInfo y)
  {
    return x.LastWriteTime.CompareTo(y.LastWriteTime);
  }
);

2009年1月22日木曜日

[.Net]スレッドっていろいろある

.Netでのスレッドは大きく分けて以下の通り
1.Threadクラスを使う
2.ThreadPoolクラスを使う
3.デリゲートを使う

となる。

完全に個人的な考えだけど、それぞれの使い分けは
Threadクラス→戻り値がいらない処理で、スレッドを止めたい事がある場合。一番細かい制御が可能。
ThreadPoolクラス→性能を求められたら使う。
デリゲート→スレッドと言ったら基本的にこれ。戻り値が簡単に取れるしコーディングしやすい。

デリゲートの使い方の手順として
1.スレッド処理関数を作る
2.スレッド処理関数と同じ引数・戻り値のデリゲートを宣言し変数を宣言する。
3.コールバック関数を作る。戻り値はvoid、引数はIAsyncResultが1つだけ。
4.スレッドを呼び出す処理を書く。

サンプルは以下に。ただし、今回は処理が終わったことだけを知りたいので、戻り値も引数もなし。
・スレッド処理関数

private static void GetImageFromWebMain(){}


・デリゲート宣言

public delegate void GetImageFromWebDelegate();
public static GetImageFromWebDelegate getImageFromWebDelegate;


・コールバック関数

private static void GetImageFromWebCallBack(IAsyncResult ar){}


・スレッドを呼び出す処理

getImageFromWebDelegate = new GetImageFromWebDelegate(GetImageFromWebMain);
getImageFromWebDelegate.BeginInvoke(new AsyncCallback(GetImageFromWebCallBack), null);


ここにはお世話になってます。

2009年1月21日水曜日

[WPF]ラジオボタンのチェック状態の設定

Windows.Formからちょっと変わっているんですね。
ラジオボタンのチェック状態を設定するために、わざわざGoogleで検索しちゃいました。

RadioButton.Checked → RadioButton.IsCheck

他にもEnabledとかなくなってるし。。。
詳しくはMSのサイトからたどって行くと言う事で。

2009年1月15日木曜日

[ASP.NET]サーバでExcelのグラフを作ったり(OWC)

こんなものがあったんですね。
Office Web Components 2003 (OWC)
2000版もXP版もあるらしい。

これを使うと、簡単にExcelファイルを生成してダウンロードさせたり、
Excelのグラフを書き出して表示したり。。。

ってちっとも簡単じゃない。
Comオブジェクトだし。

VS2005で試したのですが、単純にインストールして「Microsoft Office Web Components 11.0」を参照設定すればOKっぽいです。(PCにはOffice 2007のみインストール状態)

で、あとはここの真似してC#で書いてみました。


Response.Buffer = true;
Response.ContentType = "image/gif";

int[] aX = new int[10];
int[] aY = new int[10];

Random r = new Random();

ChartSpace cs = new ChartSpace();
ChChart chc = cs.Charts.Add(0);
ChSeries chs = chc.SeriesCollection.Add(0);
chs.Type = ChartChartTypeEnum.chChartTypeScatterLineMarkers;
chs.SetData( ChartDimensionsEnum.chDimSeriesNames
, (int)ChartSpecialDataSourcesEnum.chDataLiteral, "Chart1_Series1");
chs.SetData(ChartDimensionsEnum.chDimXValues
, (int)ChartSpecialDataSourcesEnum.chDataLiteral, aX);
chs.SetData(ChartDimensionsEnum.chDimYValues
, (int)ChartSpecialDataSourcesEnum.chDataLiteral, aY);

chc.HasLegend = true;
chc.Legend.Position = ChartLegendPositionEnum.chLegendPositionBottom;
chc.HasTitle = true;
chc.Title.Caption = "Chart1";

chc.Axes[0].HasTitle = true;
chc.Axes[0].Caption = "Y axis";

chc.Axes[1].HasTitle = true;
chc.Axes[1].Caption = "X axis";


Response.BinaryWrite((byte[])cs.GetPicture("gif", 500, 400));
Response.End();


ReleaseComObjectとかはひとまず入れてないですが、必須ですよね。
っていってもうまく表示されないぞ。。。まぁいっか。気が向いたらもうちょっと見てみます。


あと、Excelを生成してダウンロードさせる方法が、


//Excelのダウンロード
SpreadsheetClass xlsheet = new SpreadsheetClass();
// ダミーデータ
for(int i = 1 ; i< 11 ; i++)
{
xlsheet.ActiveSheet.Cells[i, i] = i.ToString();
}
String xlFileName = System.DateTime.Now.Ticks.ToString() + ".xls";
xlsheet.Export(Server.MapPath(".") + "\\" + xlFileName
, SheetExportActionEnum.ssExportActionNone
, SheetExportFormat.ssExportHTML);
Response.ContentType = "application/x-msexcel";
Response.WriteFile(Server.MapPath(".") + "\\" + xlFileName);


こっちは使い道があるかな。

2009年1月13日火曜日

[Excel]2007のファイルサイズ

Excel 2007のファイルサイズがでかすぎます。

SQL Server Management Studio で30くらいのViewからExcel形式でExportすると、それぞれのViewが1シートとなって合計30シートのファイルが作られます。

で、そのExcelの各シートを新規ブックに移動して名前を付けて保存していったのです。
データ量はまちまちで、テキストベースで3KB~187KBくらいなのですが、
作業を進めるに従って作ったExcelのファイルサイズが大きくなってきているのです。
30個目のファイルはテキストベースで3.7KB(1850文字くらい)なのですが、
ファイルサイズが3.7MB。

約1000倍!

なんか、内部的に履歴を持ってるんでしょうね。
Excel2000とExcel2003で保存し直しても小さくならないし、Netで調べたけど、対策がわからず。。。

しょうがないので、新規にExcelファイルを作って、そこにデータを貼り付けました。
ファイルサイズは28KB。

これ、どうなんですか?Microsoftさん。

2009年1月9日金曜日

[SQL Server]レコードが更新されたら更新日時を勝手に更新する

あるテーブルに作成日時と更新日時があるとします。
で、こいつらを自動で更新する方法です。

作成日時の方はInsertが発生した際のみで登録するので、
こっちの方はCreate Tableの時に「DEFAULT (getdate())」を(MSSMSなら列のプロパティの規定値またはバインド)指定するだけ。

更新日時はトリガーを使います。(他に見つからない。。)
でこんな感じでとりあえずうまく行ってます。

CREATE TRIGGER trUpdateDateTimeMemberInfo ON MemberInfo
FOR UPDATE
AS
begin
update MemberInfo
set 更新日時 = GetDate()
where MemberId = (select MemberId from inserted)
end
return

サブクエリのinsertedっていうのは処理対象のレコードって意味っぽいです。
deletedっていうのもあるらしい。