アプリケーション開発で思ったこと
by nishizakik
S M T W T F S
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
移転
宣伝するほど見に来る人がいるかどうかはわからないけど、
・文章中のソースが見づらい
・ファイルが置けない
という理由で別の場所に移転します。

http://www4.atwiki.jp/nishi/
[PR]
# by nishizakik | 2005-08-05 09:32
Service Locator Application Block
Dependency Injection とか DI とか依存性注入とかいわれるところの機能を提供する Application Block です。
Enterprise Library に組み込んで使います。
取得先

機能は、
・設定ファイルで指定したオブジェクトの生成
・実行時に指定したオブジェクトの生成
・設定ファイルで指定した静的メソッドの呼び出し
を、依存性を除去して(呼び出し元を修正せずに呼び出し先を変更可能な形で)行うことができます。

適用場面として、
・ユニットテスト時にモックオブジェクトに切り替える
・呼び出し元・先コンポーネントを独立した形で開発・保守する
点が考えられます。

More
[PR]
# by nishizakik | 2005-08-04 12:55 | Enterprise Library
ハンガリアン記法
Hungarian Notation (1)

ハンガリアン記法で前置する「型」は、言語構文上の型ではなく、意味的な区分をつけるということらしい。

考えた例では、リンゴの個数 apc 、リンゴの単価apu 、金 prc を考えて、
「prcTotal = apcProduct * apuCurrent;
は正しいけど、
prcTotal += apuCurrent;
は正しくない」
とかで、物理でやった「式の単位があっていなければ間違い」
に近いのかな。
[PR]
# by nishizakik | 2005-07-14 12:54
Samba 設定
VM にインストールした 2003 Server を Samba ドメインに参加させようとしたら
参加はできたんだけどログイン時にエラー。

調べてみたらFAQにあるとおりだった。

Samba 側の問題だったとは。XPとかはうまくいってたから、 2003 側だとばかり
思ってた。
[PR]
# by nishizakik | 2005-07-09 08:08
サイト
で、Wikiサイトを作ってみたものの、まだあまりよくわかっていない。
[PR]
# by nishizakik | 2005-07-06 08:30
不満
しかしここは開発関連のコンテンツを載せるには不便。
ソースも見づらくなってしまうし、ファイルも置けないし。

どこかいいところはないものかなぁ
[PR]
# by nishizakik | 2005-07-01 14:36
Enterprise Library - ブロック登録
というわけで、前投稿のものでは型が一致しないのでエラーとなる。
これでは不便なので、管理ツールに型を登録しようというのが今回の内容。

これまた人のをコピーしただけだが、
MS.P.EL.Configuration.Design.IConfigurationDesignManager を実装したクラス(c)を定義し、
(c-1) Register でノード(d)・参照するデータ(a)とそのXML出力型を登録。
MS.P.EL.Logging.Configuration.Design.Distributor.Sinks.SinkNode を継承したクラス(d)を定義し、
(d-1) (a) のインスタンスを参照する。
(d-2) プロパティの R/W を参照する (a) のインスタンスに委譲する。
で、このアセンブリに
[assembly : ConfigurationDesignManager(typeof(c))]
を定義しておけば勝手に使用されるとのこと。

あとは (a),(b) の入ったDLLと (c),(d) の入ったDLL を管理ツールのディレクトリにコピーすれば完成。

public class DesignManager: IConfigurationDesignManager {
 #region IConfigurationDesignManager メンバ
 public void Register(IServiceProvider serviceProvider) {
  RegisterNodeTypes(serviceProvider);
  RegisterXmlIncludeTypes(serviceProvider);
 }

 public void BuildContext(IServiceProvider serviceProvider, ConfigurationDictionary configurationDictionary) { }

 public void O‌pen(IServiceProvider serviceProvider) { }

 public void Save(IServiceProvider serviceProvider) { }
 #endregion

 private static void RegisterXmlIncludeTypes(IServiceProvider serviceProvider) {
  IXmlIncludeTypeService xmlIncludeTypeService = ServiceHelper.GetXmlIncludeTypeService(serviceProvider);
  xmlIncludeTypeService.AddXmlIncludeType(DistributorSettings.SectionName, typeof(ELTest.Sink.AnotherFlatFileSinkData));
 }
 private static void RegisterNodeTypes(IServiceProvider serviceProvider) {
  INodeCreationService nodeCreationService = ServiceHelper.GetNodeCreationService(serviceProvider);

  Type nodeType = typeof(AnotherFlatFileSinkNode);
  NodeCreationEntry entry =
   NodeCreationEntry.CreateNodeCreationEntryWithMultiples(
   new AddChildNodeCommand(serviceProvider, nodeType),
   nodeType,
   typeof(ELTest.Sink.AnotherFlatFileSinkData),
   "Another Flat File Sink");
  nodeCreationService.AddNodeCreationEntry(entry);
 }
}

[ServiceDependency(typeof(ILinkNodeService))]
public class AnotherFlatFileSinkNode : SinkNode {
 private ELTest.Sink.AnotherFlatFileSinkData _data;

 public AnotherFlatFileSinkNode() : this(new ELTest.Sink.AnotherFlatFileSinkData("Another Flat File Sink")) { }

 public AnotherFlatFileSinkNode(ELTest.Sink.AnotherFlatFileSinkData data) : base(data) {
  this._data = data;
 }

 [Browsable(false)]
 public override string TypeName {
  get { return _data.TypeName; }
 }

 [Category("General")]
 [Description("Optional.")]
 public string Header {
  get { return _data.Header; }
  set { _data.Header = value; }
 }

 [Category("General")]
 [Description("Optional.")]
 public string Footer {
  get { return _data.Footer; }
  set { _data.Footer = value; }
 }

 [Required]
 [Editor(typeof(SaveFileEditor), typeof(UITypeEditor))]
 [FilteredFileNameEditor("All files (*.*)|*.*")]
 [Category("General")]
 [Description("Required.")]
 public string FileName {
  get { return _data.FileName; }
  set { _data.FileName = value; }
 }
}
[PR]
# by nishizakik | 2005-06-29 10:41 | Enterprise Library
Enterprise Library - ブロック作成
いつまでも既存のものを使っているだけではつまらないので、作り方を試してみることにした。

まずは既存のものと同じ動作をさせてみる。というわけで、logging AB のカスタムシンクを作ってみることに。

ヘルプどおり(他のSinkのソースをコピーしたという気もするが)、MS.P.EL.Logging.Distributor.Configuration.SinkData を継承したクラス(a)を定義し、そこに動作に必要なプロパティを定義する。
MS.P.EL.Logging.Sinks.LogSink を継承したクラス(b)を定義し、
(b-1)Initialize で受け取った configurationView を退避,
(b-2)SendMessageCore で configurationView から SinkData を受け取って、ログを出力。

しかし、このままでは問題が。
デザイナに b が a を用いるということを伝えていないため、b-2 で受け取れるSinkData が CustomSinkData になってしまう(当たり前だ)。

ここまでの中間結果。
[XmlRoot("sink", Namespace=DistributorSettings.ConfigurationNamespace)]
public class AnotherFlatFileSinkData : SinkData {
 private string fileName = string.Empty;
 private string header = string.Empty;
 private string footer = string.Empty;

 public AnotherFlatFileSinkData() {}

 public AnotherFlatFileSinkData(string name) : this(name, string.Empty) {}

 public AnotherFlatFileSinkData(string name, string fileName) : this(name, string.Empty, string.Empty, string.Empty) {
  this.fileName = fileName;
 }

 public AnotherFlatFileSinkData(string name, string fileName, string header, string footer) : base(name) {
  this.fileName = fileName;
  this.header = header;
  this.footer = footer;
 }

 [XmlAttribute("fileName")]
 public string FileName {
  get { return fileName; }
  set { fileName = value; }
 }

 [XmlAttribute("header")]
 public string Header {
  get { return header; }
  set { header = value; }
 }

 [XmlAttribute("footer")]
 public string Footer {
  get { return footer; }
  set { footer = value; }
 }

 [XmlIgnore]
 public override string TypeName {
  get { return typeof(FlatFileSink).AssemblyQualifiedName; }
  set { }
 }
}

public class AnotherFlatFileSink : LogSink {
 private static object syncObject = new object();
 private LoggingConfigurationView loggingConfigurationView;
 private DefaultLogDestination defaultSink;

 public AnotherFlatFileSink() {
  this.defaultSink = new DefaultLogDestination();
 }

 public override void Initialize(ConfigurationView configurationView) {
  ArgumentValidation.CheckForNullReference(configurationView, "configurationView");
  ArgumentValidation.CheckExpectedType(configurationView, typeof(LoggingConfigurationView));

  this.loggingConfigurationView = (LoggingConfigurationView)configurationView;
 }

 protected override void SendMessageCore(LogEntry logEntry) {
  if (ValidateParameters(logEntry)) {
   try {
    WriteMessageToFile(logEntry);
   } catch (Exception e) {
    logEntry.AddErrorMessage(e.ToString());
    throw;
   } catch {
    logEntry.AddErrorMessage("UnknownError");
   }
  }
 }

 private bool ValidateParameters(LogEntry logEntry) {
  AnotherFlatFileSinkData anotherFlatFileSinkData = GetAnotherFlatFileSinkDataFromCursor();

  bool valid = true;

  if (anotherFlatFileSinkData.FileName == null || anotherFlatFileSinkData.FileName.Length == 0) {
   valid = false;
   logEntry.AddErrorMessage("FileSinkMissingConfiguration");
   this.defaultSink.SendMessage(logEntry);
  }

  return valid;
 }

 private AnotherFlatFileSinkData GetAnotherFlatFileSinkDataFromCursor() {
  SinkData sinkData = loggingConfigurationView.GetSinkData(ConfigurationName);
  ArgumentValidation.CheckExpectedType(sinkData, typeof (AnotherFlatFileSinkData));

  return (AnotherFlatFileSinkData) sinkData;
 }

 private void WriteMessageToFile(LogEntry logEntry) {
  AnotherFlatFileSinkData anotherFlatFileSinkData = GetAnotherFlatFileSinkDataFromCursor();
  string fileName = anotherFlatFileSinkData.FileName;
  string header = anotherFlatFileSinkData.Header;
  string footer = anotherFlatFileSinkData.Footer;

  string directory = Path.GetDirectoryName(fileName);
  if (directory.Length == 0) {
   directory = AppDomain.CurrentDomain.BaseDirectory;
  }
  if (!Directory.Exists(directory)) {
   Directory.CreateDirectory(directory);
  }

  using (FileStream fileStream = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)) {
   using (StreamWriter writer = new StreamWriter(fileStream)) {
    lock (syncObject) {
     if (header.Length > 0) { writer.WriteLine(header); }
     writer.WriteLine(FormatEntry(logEntry));
     if (footer.Length > 0) { writer.WriteLine(footer); }

     writer.Flush();
    }
   }
  }
 }
}
[PR]
# by nishizakik | 2005-06-29 10:35 | Enterprise Library
Enterprise Library(続き)
Flat File Sink で2回目以降書かれなかったと思っていたけど、書かれていた。

別のディレクトリに。

なぜか ${Oracle_Home}\bin に書かれているので、どこかで chdir しているのかもしれない。
依然として謎なので、検索してみようかな。
[PR]
# by nishizakik | 2005-06-17 09:08 | Enterprise Library
Enterprise Library
テストプログラムを作ってみた。

設定さえわかれば比較的簡単に作れることがわかった。

・Windows Forms
設定は app.config に書いているのに対し、各 AB が用いる config ファイルは bin/debug になければならないため、とりあえず手でコピーした。
おそらくビルドスクリプトを書くことになるのかなぁ。

・イベントログに何か書かれる
Enterprise LibraryでEvent Logのエラーを抑えるバッチファイル

・Logging AB でファイルに書く場合
複数回 Write しても最初の分しか書かれなかった。イベントログに書くように設定したら毎回書かれたので、プログラム側には問題なさそう。
設定が間違っているのかも。
[PR]
# by nishizakik | 2005-06-15 17:29 | Enterprise Library