LoginSignup
0
0

More than 3 years have passed since last update.

Coreで簡易サーバーアプリを作って複数の機器を連携させる

Posted at

はじめに

設置する機器が複数ある場合など、システムがある程度の規模になった場合、複数のアプリケーションを連携させたくなることがあります。
<例>
・画像をスキャンするアプリケーション
・送信された画像を演出に用いるアプリケーション

同じPCだけでなく、違うPCで連携させたいことがあります。
<例>
・画像撮影用PC
・演出用PC

シンプルなやり方をとりたいので、
.Net Coreでサーバーアプリケーションを作り、通信はhttp(あるいはhttps)を使い、アプリケーション間で連携することにします。

必要なもの

開発環境・実行環境用 共にWindows PCを使用し、
サーバー側PCの実行環境にIIS(Internet Information Services)を使用します。
クライアント機器は、http通信が出来るならばなんでも利用出来そうです。

※多数(具体的には20台より多く)の機器から接続する場合、
サーバーにデスクトップ用のWindowsを使用するとライセンス違反となる場合があるので、その場合はLinux等のOS上に実行環境を構築します。

サーバー側PC

サーバーアプリケーションを配置します。
.Net Coreのランタイム等が必要になります。
https://dotnet.microsoft.com/download/dotnet-core
・開発用に .NET Core SDK
・実行環境用にASP.NET Core Hosting Bundle
をダウンロードし、実行用にIISをインストールします。

クライアント側PC

クライアント側のアプリケーションに、サーバーアプリケーションと通信する機能を実装します。
サーバーアプリを配置しているPCと同じPCでも構いません。

サーバーアプリの作成

Visual Studio上で新しいプロジェクトを作成し、
プロジェクトテンプレートに「ASP .Net Core アプリケーション(C#)」を、
追加のプロジェクトテンプレートに「API」を選択してみます。

以下のクラスを追加します。

SampleItem.cs
    public class SampleItem
    {
        /// <summary>
        /// ID(連番)
        /// </summary>
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [Key]
        public uint ID { get; set; }

        /// <summary>
        /// 名前
        /// </summary>
        [MaxLength(128)]
        public string Name { get; set; }

    (略)
    }


SampleDbContext.cs
public class SampleDbContext: DbContext
{
    public DbSet<SampleItem> Samples { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Filename=ImageDatabase.sqlite");
        base.OnConfiguring(optionsBuilder);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<SampleItem>().ToTable("SampleItem", "test");
        base.OnModelCreating(modelBuilder);
    }


また、Startupクラスを以下のように編集します。

Startup.cs
    public class Startup
    {
        /// <summary>
        /// appsettings.jsonなどから読み込んだこのアプリの設定情報
        /// </summary>
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration)
        {
            // appsettings.jsonなどから読み込んだ設定
            Configuration = configuration;
        }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<AppSetting>(Configuration);

            // DBコンテキストの作成
            services.AddEntityFrameworkSqlite().AddDbContext<SampleDbContext>();

            // DBのテーブルが無ければ作る。既にある場合はそのまま
            using (var client = new SampleDbContext())
            {
                client.Database.EnsureCreated();
            }
            services.AddControllersWithViews();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            (※省略)
        }
    }


機能の実装

投稿した画像を保存する機能、取得する機能を実装します。

APIController.cs
        [Serializable]
        [DataContract]
        public class ScanImageGetInfo
        {
            [DataMember(Name = "id")]
            public uint ID { get; set; }
            (略)
        }

        [HttpPost]
        public IActionResult PostImage(IFormFile Targetfile, int MachineID, int ImageCodeID)
        {
            if (Targetfile == null)
            {
                return new BadRequestResult(); // HTTPステータスコード 400
            }

            string savePath = SaveFileToWorkFolder(Targetfile, MachineID, ImageCodeID);

            //ファイルをダウンロード
            return new EmptyResult(); // HTTPステータスコード 200
        }

        /// <summary>
        /// 指定したIDの画像データを取得
        /// </summary>
        /// <param name="Id">PopImageで取得したレコードのID</param>
        /// <returns></returns>
        public IActionResult GetImage(int ID)
        {
            using (var context = new SampleDbContext())
            {
                var item = context.ScanImages.FirstOrDefault(x => x.ID == ID);
                if (item == null) return new BadRequestResult();
                filePath = folder + "\\" + item.FilePath;
                fileName = item.Name;
            }

            return File(GetStream(filePath), "image/png", Path.GetFileName(fileName));
        }

        // ファイルをこのPC上に保存する関数
        string SaveFileToWorkFolder(){
                (略)
        }

        // FileStreamを全て読み込み、MemoryStreamとして返す
        private Stream GetStream(String filepath)
        {
            var memory = new MemoryStream();
            using (var stream = new FileStream(filepath, FileMode.Open))
            {
                stream.CopyTo(memory);
            }
            memory.Position = 0;
            return memory;
        }


これで/api/postimageにアクセスするとファイルの保存、/api/getimageにアクセスするとファイルの取得が出来るようになりました。

ファイルの投稿(クライアントスキャナアプリ側)

.Net Frameworkで作成したアプリケーションですが、
以下のように引数を与えてHttpのPostを送信しています。

画像の投稿を行うHttpPostImage()関数
        async public Task<string> HttpPostImage(string imageFilePath, int imageCodeID)
        {
            //File.WriteAllText(System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\log2.txt",
            //    "postimage" + "\n");

            // 送信を行います。
            // POSTする情報
            //WWWForm form = new WWWForm();
            //form.AddField("userId", userId);

            string APIURL = "http://"
                + Properties.Settings.Default.ServerURL
                + ":"
                + Properties.Settings.Default.ServerPort
                + "/API/PostImage";

            using (var stream = File.OpenRead(imageFilePath))
            using (var fileContent = new StreamContent(stream))
            using (var content = new MultipartFormDataContent())
            using (var client = new HttpClient())
            {
                fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
                {
                    Name = "Targetfile",
                    FileName = Path.GetFileName(imageFilePath),
                };
                fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");

                content.Add(fileContent);
                content.Add(new StringContent(Properties.Settings.Default.MachineID.ToString()), "MachineID");
                content.Add(new StringContent(imageCodeID.ToString()), "ImageCodeID");

                using (var response = await client.PostAsync(APIURL, content))
                {
                    return await response.Content.ReadAsStringAsync();
                }
            }
        }


ファイルの取得(クライアント演出アプリ側)

Unityのアプリケーションですが、以下のようにしてGetを送信し、テクスチャ画像を取得することが出来ます。

画像の取得を行うコルーチン関数
        IEnumerator AccessCoroutine()
        {
            // Request
            string getImageUri = "http://" + _serverURL + ":" + _serverPort + ServerGetImageAPI;

            // 処理終わるまでループ
            while (isRunning)
            {

                      (略 idに取得したい画像のidを入れる)
                        string queryString = "?id=" + id;
                        // Texture2Dを作成
                        using (UnityWebRequest webGetImageRequest = UnityWebRequestTexture.GetTexture(getImageUri + queryString, true))
                        {
                            yield return webGetImageRequest.SendWebRequest();
                            if (webGetImageRequest.isNetworkError || webGetImageRequest.isHttpError)
                            {
                                Debug.Log(webGetImageRequest.error);
                            }
                            else
                            {
                                // Get downloaded asset bundle
                                Texture2D texture = DownloadHandlerTexture.GetContent(webGetImageRequest);
                                ( テクスチャー画像の処理)
                            }
                        }

                    }
                }
                yield return new WaitForSeconds(1.0f);
            }
        }


これらのプログラムを組み合わせて、PC間で連携したひとつのシステムを作ることが出来ます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0