none
NET2.0 C#のコンソールアプリケーションで、CGIのアプリケーションは作成できるでしょうか? RRS feed

  • 質問

  • NET2.0 C#のコンソールアプリケーションで、CGIのアプリケーションは作成できるでしょうか?

     

    ↓こんなプログラムでは、CGIのように動作します。

    static void Main(string[] args)

    {
     Console.WriteLine("HEETP/1.0 200 OK");
     Console.WriteLine("Content-Type: text/html\n");
     Console.WriteLine("<html>");
     Console.WriteLine("<body>");
     Console.WriteLine("<H1>テスト</H1>");
     Console.WriteLine("</body>");
     Console.WriteLine("</html>");
    }

     
    環境変数も取り込めます。

    IDictionary idict = System.Environment.GetEnvironmentVariables();
    IDictionaryEnumerator denum = idict.GetEnumerator();
     while (denum.MoveNext())
     {
             Console.WriteLine("{0} = {1}", denum.Key, denum.Value + "<br>");
     }

    これで、GETの値は、取れました。

    "REQUEST_METHOD=POST"もセットされていました。

     

    通常のCでは、標準入力stdinからPOSTの値を取るのでですが、

    C#では、Console.In.ReadToEnd()で取れるかと思ったのですが、

    止まってしまいます。

    POSTの値をとる方法は、ないでしょうか?

     

    C#では、CGIのアプリケーションは作成できないのでしょうか?

     

     

    2008年12月7日 11:48

回答

  •    K.Takaoka

    返信ありがとうございます。

     

    >少し脱線しますが、ASP.NET のフレームワーク上で、HTTP のレスポンス全体を生成する手法はいくつかあります。

    >IDE から簡単に作成できるものとしては、*.aspx ではなくて *.ashx ファイルを作成する方法です。

    「ジェネリックハンドラ」ですね。これなんの事か分からず気にもしてませんでした。

     これは、使えそうです。

    ありがとうございました。

    2008年12月10日 2:35

すべての返信

  • 簡単に言えばCGIは、標準入力から入力されてたものに対して(環境変数というときもありますが)、標準出力に出力を返すプログラムです。

    Console.WriteLineで標準出力で出力を返す部分はできているようですね。
    Console.ReadLineで標準入力から入力はできませんか?

    2008年12月8日 0:14
  •  

      返信ありがとうございます。

     

    Console.In.ReadLine();

    Console.ReadLine();

     

    両方ためしましたが、どちらも、止まってしまいます。

    前後に、ログ出力して確認しています。

    ためしに、コマンドラインから実行すると、キー入力待ちになります。

    IISサーバには、DOS画面が表示されていませんが、

    HTTPから起動しても、キー入力待ちになって止まっているようなきがします。

    確信はありません。想像です。

     

    2008年12月8日 2:12
  • 外池と申します。めちゃくちゃ簡単な例ですが、

     

    hoge.exeを

    Code Snippet

    namespace hoge {
        class Program {
            static void Main(string[] args) {
                Console.WriteLine("hoge");        
            }
        }
    }

     

    twice.exeを

    Code Snippet

    namespace twice {
        class Program {
            static void Main(string[] args) {
                string s = Console.ReadLine();
                Console.WriteLine(s + s);
            }
        }
    }

     

    としてビルド、2つのexeファイルを同じ場所に置いて、コマンドプロンプトでhoge | twiceとやれば、"hogehoge"と出力されます。

     

    これと同じような確認方法できませんか?

     

     

    2008年12月8日 4:25
  •  外池様

    返信ありがとうございます。

    試してみました。

    コマンドラインからの標準入力、標準出力は、問題ありませんでした。

    IISのPOSTデータを標準入力からは取り込めないようです。

     

    作成中のプログラムもコマンドラインで起動すると、キー入力待ちになり、

    キー入力で、POSTするデータを入力すると期待通りの動作をして標準出力してくれます。

     

    2008年12月8日 5:12
  • こんにちは!(^^)!ふ~です。

     

    >こんなプログラムでは、CGIのように動作します。

     

    見かけは同じでも、コンソールアプリとCGIでは、全く別の動作環境です。

    コンソールアプリでCGIは作成できません。普通は。。。

     

    static void Main(string[] args)

    {
     Console.WriteLine("HEETP/1.0 200 OK");
     Console.WriteLine("Content-Type: text/html\n");
     Console.WriteLine("<html>");
     Console.WriteLine("<body>");
     Console.WriteLine("<H1>テスト</H1>");
     Console.WriteLine("</body>");
     Console.WriteLine("</html>");
    }

     

    このようなテキストファイルをCGITest.cgiとして、Webの実行ディレクトリに

    置いて「http://localhost/Samples/CGITest.cgi」などと、CGI実行すれば、

    『HTTP 500 内部サーバー エラー』となります。

     

    また、CGITest.exe ->をCGITest.cgiに拡張子を変更しても論外で駄目です。

     

    IISサーバーでも、CGI環境を設定すれば、CGIは実行できますが、Perlで作成

    する場合が一般的です。

    KoshiさんのコンソールアプリでCGIを作成する手法をご説明頂けないでしょうか?

     

    >C#では、Console.In.ReadToEnd()で取れるかと思ったのですが、

     

       using System.IO;


       TextWriter stringWriter = new StringWriter();
       TextReader stringReader =
         new StringReader(stringWriter.ToString());
       Console.WriteLine("Input={0}", stringReader.ReadToEnd());

       こんな使い方ではと思います。

     

    ◆ご参考資料 ( C言語‐>C#言語対応表 I/O 関連)

    http://support.microsoft.com/default.aspx/kb/313836/ja

    2008年12月8日 5:54
  •  !(^^)!ふ~ さんからの引用

    見かけは同じでも、コンソールアプリとCGIでは、全く別の動作環境です。

    コンソールアプリでCGIは作成できません。普通は。。。


    ん?普通ではない方法とはどの様な方法をおっしゃっられてますか?

    2008年12月8日 6:24
  •  

     こんにちは!(^^)!ふ~様

    返信ありがとうございます。

     

    開発は、VS2500のC#コンソールアプリケーションで行っています。

    サーバは、WindowsXP Sp3 .NET Framework3.5 Sp1で動作確認しています。

    .NET Farmework3.5 Sp1以前ですと、セキュリティポリシーで動作しません。

    IIS上で動作するセキュリティポリシーの設定は、やり方がわからず動作しません。

    現在サーバに、.NET Farmework3.5 Sp1必須の状態です。

    .NET Farmework3.5 Sp1ですと、ネットワーク上(ローカルネットワーク含めて)セキュリティポリシーの設定が不要で、

    通常のネイティブコードと同じ動作します。↓の.NET 3.5のダウンロードページに書いてありました。

    http://www.microsoft.com/downloads/details.aspx?familyid=AB99342F-5D1A-413D-8319-81DA479AB0D7&displaylang=ja

     

    IISの仮想ディレクトリの設定は、通常の「スクリプト及び実行可能ファイル」で動作します。

    これで、POSTを得る以外は、通常のCGIアプリケーションとして動作しています。

     

     

    2008年12月8日 6:27
  • こんばんは!(^^)!ふ~です。

     

    koshiさんの言われます

     

    >↓こんなプログラムでは、CGIのように動作します。

    >static void Main(string[] args)

    >{
    > Console.WriteLine("HEETP/1.0 200 OK");
    > Console.WriteLine("Content-Type: text/html\n");
    > Console.WriteLine("<html>");
    > Console.WriteLine("<body>");
    > Console.WriteLine("<H1>テスト</H1>");
    > Console.WriteLine("</body>");
    > Console.WriteLine("</html>");
    >}

     

    ですが、普通ドットネットの世界では、ASP.NET Webアプリケーション

    を使い以下のコードと思います。

     

    ◆起動方法

    http://localhost/Default.aspx

     

    ◆コード

    using System;
    namespace WebAppTest
    {
     public partial class _Default : System.Web.UI.Page
     {
      protected void Page_Load(object sender, EventArgs e)
      {
       Response.Write("HEETP/1.0 200 OK");
       Response.Write("Content-Type: text/html\n");
       Response.Write("<html>");
       Response.Write("<body>");
       Response.Write("<H1>テスト</H1>");
       Response.Write("</body>");
       Response.Write("</html>");
      }
     }
    }

     

    この辺の考え方がどうも見えないのですが?

    2008年12月8日 8:39
  • こんにちは。中川俊輔です。

     

    皆様、回答ありがとうございます。

     

    koshiさん、フォーラムのご利用ありがとうございます。

    POSTの取得はConsole.In.ReadToEndだとうまくいかないようですね。

    バッファの確保や文字列変換に手間がかかるようですがConsole.OpenStandardInput メソッドを

    使ってみてはどうでしょうか?

    Console.OpenStandardInput

    http://msdn.microsoft.com/ja-jp/library/tx55zca2.aspx

     

     

    この投稿は現状のまま何の保証もなく掲載しているものであり、何らかの権利を許諾するものでもありません。

    コミュニティにおけるマイクロソフト社員による発言やコメントは、マイクロソフトの正式な見解またはコメントではありません。詳しくは http://www.microsoft.com/japan/communities/msp.mspx をご覧ください。

    2008年12月8日 8:39
  •  こんばんは!(^^)!ふ~様

    たびたび返信ありがとうございます。

     

    たしかに、ASP.NETを使った方が良いのは分かっているのですが、

    私のやっている事は、ClickOnceで作成したアプリケーションがあります。顧客から、制限付きで良いからWeb化できないかと

    相談されて、簡単なプロトタイプを、ASP.NETで一部機能を作成しました。

    ASP.NETは、便利なのですが、デザインで苦労しそうなのと、バイナリデータを作成してダウンロードさせたりするので、

    C#のコンソールアプリケーションで出来ないかなと思って調べています。

    C#に、こだわるのは、ClickOnceのコードを流用したいからです。

     

    --------------------------------------------------------------

    namespace WebAppTest
    {
     public partial class _Default : System.Web.UI.Page
     {
      protected void Page_Load(object sender, EventArgs e)
      {
       Response.Write("HEETP/1.0 200 OK");
       Response.Write("Content-Type: text/html\n");
       Response.Write("<html>");
       Response.Write("<body>");
       Response.Write("<H1>テスト</H1>");
       Response.Write("</body>");
       Response.Write("</html>");
      }
     }
    --------------------------------------------------------------

    すみません。これVS2005のASP.NETで出来るでしょうか?

    V2005には、XMLのデザイン部が付いて回っていて、これが、排除できれば

    ほとんどの部分をASP.NETで作成できるのですが

    2008年12月8日 9:08
  •  中川俊輔様

    返信ありがとうございます。

    Console.OpenStandardInput ためしてみます。

    結果が出ましたら報告します。

     

     

     

    2008年12月8日 9:13
  • こんばんは!(^^)!ふ~です。

     

    >ClickOnceで作成したアプリケーション

     

    JAVAのアプレット的な使い方を考えられていらっしゃるようですね。

    そうですか、納得いたしました。

     

    >すみません。これVS2005のASP.NETで出来るでしょうか?

    >V2005には、XMLのデザイン部が付いて回っていて、これが、排除できれば

    >ほとんどの部分をASP.NETで作成できるのですが

     

    VS2005のASP.NETも使われます。

    『Response.Write』は、Webアプリで使われます。欠点は、これで、HTML

    コードを作成すると、既にあるコードの途中にコードを入れられない事です。

     

    途中からコードを入れるには、パネルコントロールを任意の場所に貼り付け、

    その中にHTMLコードを動的に記述できます。下記コードはとても便利です。

     

    Code Snippet

    // パネルコントロール1へ動的にHTMLコードを入れる。

    Panel1.Controls.Add( new LiteralControl( HTMLコードの文字列 ));

    // 使用例

     Panel1.Controls.Add(new LiteralControl( (string)(dv[i]["日付"]) +
                    " (" + (string)(dv[i]["曜日"]) + ") <font color=#FF0000>定休日</font>" + "<br>\n") );

     

     

     

    これですと、デザイナーの方に、パネルコントロールでスペースを空けて頂くだけです

    からお打合わせも簡単です。

     

    以上

     

    2008年12月8日 9:39
  •   中川俊輔様

     

    Console.OpenStandardInput();ためしてみした。

    結果は、以前と同様でした。

    コマンドラインでは、動作しますが、HTTPのCGIとしての動作は、

    Readで止まってしまいます。

    Stream strm = Console.OpenStandardInput();

      StreamReader stmr = new StreamReader(strm);

     ログ出力
       string sline = stmr.ReadLine();
     ログ出力

    前後にログを出力して確認しました。

    stmr.ReadToEnd();も確認しました。

    ゴミでも表示して先に進んでくれる事を期待したのですが、

    読み込み操作で止まってしまいます。

    2008年12月8日 10:00
  •  koshi さんからの引用

    私のやっている事は、ClickOnceで作成したアプリケーションがあります。顧客から、制限付きで良いからWeb化できないかと相談されて、簡単なプロトタイプを、ASP.NETで一部機能を作成しました。

    ASP.NETは、便利なのですが、デザインで苦労しそうなのと、バイナリデータを作成してダウンロードさせたりするので、C#のコンソールアプリケーションで出来ないかなと思って調べています。

    C#に、こだわるのは、ClickOnceのコードを流用したいからです。

     バイナリデータのダウンロードは、ASP.NET でも使用できますよ?

     デザインで苦労しそう、というのは、グリッドモードにしているからではないですか?

    # 余計に苦労しているようにしか思えないです。。。

    2008年12月8日 10:06
  • 外池です。

     

    Koshiさんの書かれていることを拝見するに、私もCGIが一番良いと思います。特に、バイナリーデータを吐き出す本体の応答や、これに先立つヘッダーの送信をきめ細かく記述したければ、かつ、.Netでやりたければ、C#かVBで、コンソール・アプリとしてexeファイルをビルドして使うことで解決できるはずです。

     

    Consoleクラスの標準入出力を、特に、入力について、Console.ReadLine、Console.In.Readホゲホゲを使おうとすると、これらは文字コード(Encoding)と不可分です。ですので、バイナリーデータを使うことが大変面倒だと思います。先ほどの私の例では、文字のみの扱い(一行の終端が明快)だったので、何の問題もなく動きましたが。

     

    一般的な入力ストリームとして扱いたければ、中川さんの仰るOpenStandardStreamでStreamを取得するのが一番だと思います。これがあれば、文字データは、さらにStreamReaderクラスを取得して読めばよし、バイナリーデータは直にReadすればよし、です。

     

     

     

     

    2008年12月8日 10:10
  •   こんばんは!(^^)!ふ~様

    たびたび返信ありがとうございます。

     

    VB.NETは勉強不足でした。

    これが、できるのなら、デザイナーが作成したHTMLファイルを読み込んで、一部コードを変更して出力できますね。

    一番の目的は、これでした。

     

    バイナリーファイルは、特別なコントロールが必要で、ASP.NETでは組み込めないので、

    GETを使ったC# CGIでなんとかしようと思います。

    あとがとうございました。

     

    でも、C#で、CGI作成できるのか?

    は、きになります。

    Microsoftから、サポート外です。って言ってくれると楽になります。

     

    2008年12月8日 10:12
  • 外池です。追加です。

     

    えっとですね、Encodingが絡む形でいきなり読もうとせずにですね、バイト単位で一度取得してみてはいかがですか? あるいは、Encoding.ASCIIを指定して、一文字ずつ読むとか。(これなら、ゴミみたいな感じかもしれませんが、クライアントからのメッセージが拾えるのでは?)

     

    私の予感では、ReadLineをしようとしても、行の終端が検知できないまま、待っている状態ではないかと・・・。

     

     

     

    2008年12月8日 10:16
  •  

       Jitta

    返信ありがとうございます。

    デザインにうるさい顧客なので、あまりコードに、デザインを、組み込むたくなかったのです。

    ASP.NETは、勉強不足でした。

     

     

     

     

    2008年12月8日 10:21
  • こんばんは!(^^)!ふ~です。

     

    ◆ご参考資料です。

     

    ClickOnceアプリの起動時にパラメータを渡すには?

    http://www.atmarkit.co.jp/fdotnet/dotnettips/514clickoncmdarg/clickoncmdarg.html

     

    2008年12月8日 10:21
  •   外池様

    返信ありがとうございます。

     

    >私の予感では、ReadLineをしようとしても、行の終端が検知できないまま、待っている状態ではないかと・・・。

    ビンゴでした。

    1バイトずつ読込んだら動作しました。

    ReadToEndで出来ないので、1バイトずつ読込むのはやっていませんでした。

     

    ありがとうございました。

     

    これで、C#のコンソールアプリケーションで、CGIアプリケーションは動作しますね。

     

     

     

    2008年12月8日 10:41
  •   !(^^)!ふ~様

     返信ありがとうございます。

    1バイトづつの読み込みで、標準入力のPOSTデータ読めました。

    お騒がせしました。

     

    おかげさまで、ASP.NETと、C#コンソールアプリケーションの組み合わせで

    プログラで楽ができそうです。

     

    ありがとうございました。

     

    まとめです。

    C#コンソールアプリケーションで、CGIプログラムを動作させるには、

    .NET Framework3.5 Sp1が必要

     

    環境変数は、

          string dt  = System.Environment.GetEnvironmentVariable(name);
    で取れる。

    GETかPOSTは、

    String strMethod =
                    Environment.GetEnvironmentVariable("REQUEST_METHOD");

    で取れる。

    strMethod == "GET"なら、Environment.GetEnvironmentVariable("QUERY_STRING ");で取れる。

    strMethod == "POST"なら、標準入力から1バイトづつ読込む

     

    皆様ありがとうございました。

     

    2008年12月8日 10:51
  • > すみません。これVS2005のASP.NETで出来るでしょうか?

    > V2005には、XMLのデザイン部が付いて回っていて、これが、排除できれば

    > ほとんどの部分をASP.NETで作成できるのですが

     

    少し脱線しますが、ASP.NET のフレームワーク上で、HTTP のレスポンス全体を生成する手法はいくつかあります。

    IDE から簡単に作成できるものとしては、*.aspx ではなくて *.ashx ファイルを作成する方法です。

     

    Code Snippet
    <%@ WebHandler Language="C#" Class="TestHandler" %>
     
    using System;
    using System.Web;
    using System.Text.RegularExpressions;
    using System.Collections.Generic;
    using System.Drawing;
    public class TestHandler : IHttpHandler
    {
        void IHttpHandler.ProcessRequest(HttpContext context)
        {
            // HTTP Header はプロパティから設定, Content-Type 以外も色々
            context.Response.ContentType = "image/jpeg";
     
            // レスポンスとして画像を出力などなど
            img.Save(context.Response.OutputStream, ImageFormat.Kpeg);
        }
    }

     

     

    2008年12月9日 13:36
  •    K.Takaoka

    返信ありがとうございます。

     

    >少し脱線しますが、ASP.NET のフレームワーク上で、HTTP のレスポンス全体を生成する手法はいくつかあります。

    >IDE から簡単に作成できるものとしては、*.aspx ではなくて *.ashx ファイルを作成する方法です。

    「ジェネリックハンドラ」ですね。これなんの事か分からず気にもしてませんでした。

     これは、使えそうです。

    ありがとうございました。

    2008年12月10日 2:35