webserver 를 이용해 파일 업로드 기능을 만들다가 남겨놓으면 좋을거 같아 남깁니다.

 

코드는 아래 받으면 되고 Visual Studio 2017버전으로 작성이 되었습니다.

 

DotNetCoreFileUpload.zip
1.54MB

 

기본적인 코드를 소개(?)하겠습니다.

 

1. web server project create

   1.1 Controllers folder - new controller 

   1.2 Code

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.IO;

namespace WebServer.Controllers
{
    [ApiController]
    public class FIleUploadController : ControllerBase
    {
        [HttpPost]
        [Route("api/fileuload")]
        public ActionResult FileUpload([FromForm]FileUploadModel std)
        {
            // Getting Name
            string name = std.Name;
            // Getting Image
            var image = std.File;
            // Saving Image on Server
            if (image.Length > 0)
            {
                using (var fileStream = new FileStream(image.FileName, FileMode.Create))
                {
                    image.CopyTo(fileStream);
                }
            }

            return Ok(new { status = true, message = "Student Posted Successfully" });
        }
    }

    public class FileUploadModel
    {
        public string Name { get; set; }
        public IFormFile File { get; set; }
    }
}

2. windows forms project create

   2.1 Form1.cs Code(Ui는 첨부파일 참고)

using System;
using System.IO;
using System.Net.Http;
using System.Windows.Forms;

namespace WindowClient
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnFIleSelect_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog()
            {
                FileName = "Select a text file",
                Filter = "Text files (*.txt)|*.txt",
                Title = "Open text file",
                //InitialDirectory = 
                RestoreDirectory = true
            };

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                //Get the path of specified file
                tbxFile.Text = openFileDialog.FileName;

                //Read the contents of the file into a stream
                //var fileStream = openFileDialog.OpenFile();

                //using (StreamReader reader = new StreamReader(fileStream))
                //{
                //    fileContent = reader.ReadToEnd();
                //}
            }
        }

        private async void btnFileUpload_Click(object sender, EventArgs e)
        {
            byte[] fileBytes = null;
            try
            {
                using (FileStream fileStream = new System.IO.FileStream(tbxFile.Text, FileMode.Open))
                {
                    fileBytes = new byte[fileStream.Length];
                    fileStream.Read(fileBytes, 0, fileBytes.Length);
                    
                    HttpClient httpClient = new HttpClient();
                    MultipartFormDataContent form = new MultipartFormDataContent();

                    form.Add(new StringContent("John" /* value */), "Name" /* class member name */);
                    form.Add(new ByteArrayContent(fileBytes, 0, fileBytes.Length), "File" /* class member name */, "wwwFile" /* value(file name) */);
                    HttpResponseMessage response = await httpClient.PostAsync(tbxURL.Text, form);

                    if (response.IsSuccessStatusCode)
                    {
                        // process....
                    }
                }
            }
            catch (Exception ex)
            {
                // Exception ...
            }

        }
    }
}

테스트

1. WebServer 프로젝트 디버깅 시작 

2. WindowsClient 프로젝트 디버깅 시작 

 

참고 자료

https://dottutorials.net/dotnet-core-web-api-multipart-form-data-upload-file/

블로그 이미지

레몬도리 LemonDory

개발자의 이야기

댓글을 달아 주세요

출처 : https://stackoverflow.com/questions/34884854/convert-listint-to-byte

 

Convert list<int[]> to byte[]</int[]>

How to convert list<int[]> to byte[]? I could use this: byte[] bytes = lista.SelectMany(BitConverter.GetBytes).ToArray(); But it works only for list. If you have few ideas - m...</int[]>

stackoverflow.com

List -> byte[]

byte[] bytes = lista .SelectMany(x => x) .SelectMany(BitConverter.GetBytes) .ToArray();

 

byte[] -> List

List<int> list = bytes

.Select((item, index) => new {item, index})

.GroupBy(x => x.index/4)

.Select(g => g.Select(x => x.item).ToArray())

.Select(x => BitConverter.ToInt32(x, 0)) .ToList();

 

 

블로그 이미지

레몬도리 LemonDory

개발자의 이야기

댓글을 달아 주세요

dotnet 버전별 define하기

2019. 5. 16. 11:25

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

무료 .NET dll 디컴파일 프로그램 dotPeek


https://www.jetbrains.com/decompiler/

블로그 이미지

레몬도리 LemonDory

개발자의 이야기

댓글을 달아 주세요

RollingFileAppender class

addFilter

public void addFilter(Filter newFilter)
Add a filter to end of the filter list.

Specified by:
addFilter in interface Appender


위 filter에 log level을 설정할 수 있는데 검색하다 발견한 내용들.


 ALL    DEBUG   INFO    WARN    ERROR   FATAL   OFF
All                        
DEBUG  DEBUG                  
INFO   INFO   INFO               
WARN   WARN   WARN   WARN           
ERROR  ERROR  ERROR  ERROR  ERROR      
FATAL  FATAL  FATAL  FATAL  FATAL  FATAL  
OFF    OFF    OFF    OFF    OFF    OFF    OFF

위와 같은 모양으로 되어 있는 것으로 설정을 해봤다. 


LevelMinLevelMax를 All로 지정하면 모두가 나올 줄 알았지만 나오지 않았다.

LevelMin을 DEBUG, LevelMax를 ERROR로 테스트를 할 경우 위에  조건대로 로그가 생성되는 것을 확인하였다. 


로그가 생성이 안된다고 Log4Net이 문제라 생각하지말고 레벨 설정, 파일 경로 등을 설정해보라.


참고 : https://stackoverflow.com/questions/8926409/log4net-hierarchy-and-logging-levels

블로그 이미지

레몬도리 LemonDory

개발자의 이야기

댓글을 달아 주세요

    "_id" : ObjectId("5bee629dee0fc9d332b2107b"), 

    "no" : NumberLong(30001), 

    "name" : "레몬과일가게", 

    "products" : [

        {

            "id" : NumberLong(50001), 

            "name" : "레몬", 

            "price" : NumberInt(4), 

        }, 

        {

            "id" : NumberLong(50002), 

            "name" : "사과", 

            "price" : NumberInt(12), 

        }, 

        {

            "id" : NumberLong(50003), 

            "name" : "파인애플", 

            "price" : NumberInt(3), 

        }, 

        {

            "id" : NumberLong(50004), 

            "name" : "귤", 

            "price" : NumberInt(3), 

        }

    ]

mongodb 에서   30001번 과일가게에서 레몬의 가격을 변경하기 위한 코드 샘플

var filter = Builders<store>.Filter.Where(c => c.no == 30001 && c.products.Any(e => e.id == 50001));

var update = Builders<player>.Update.Set(x => x.products[-1].price, 2000);

var option = new UpdateOptions() { IsUpsert = false }; 


출처 : https://stackoverflow.com/questions/31453681/mongo-update-array-element-net-driver-2-0


https://stackoverflow.com/questions/31277679/how-to-find-and-update-an-item-inside-of-a-array-of-an-object-in-an-array-acc

블로그 이미지

레몬도리 LemonDory

개발자의 이야기

댓글을 달아 주세요


mongodb collection을 protobuf class로 가져오려고 하던 중에 List 형태를 가져와보려고 많은 시간을 소비해 가며 보던 중에 .proto로 gen할 때 자세히 보니 repeated 값들이 readonly로 생성 되는 것을 보았다.


여기 저기 검색하던 중에 protobuf를 본 외국인의 글을 발견했다.(질문자는 다른 방법이 필요했던 거였지만 아래 더 자세한 설명을 해준 답변자의 답변이 눈에 들어왔다)

링크 : https://stackoverflow.com/questions/16617933/protobuf-net-generated-class-from-proto-is-repeated-field-supposed-to-be-re


This was a new issue for us as well after updating our proto-net executable and related files. It was new behavior we hadn't experienced before.

After a little digging in csharp.xslt, we found the definition for 'repeated' fields:

<xsl:template match="FieldDescriptorProto[label='LABEL_REPEATED']">
    <xsl:variable name="type"><xsl:apply-templates select="." mode="type"/></xsl:variable>
    <xsl:variable name="format"><xsl:apply-templates select="." mode="format"/></xsl:variable>
    <xsl:variable name="field"><xsl:apply-templates select="." mode="field"/></xsl:variable>
    private <xsl:if test="not($optionXml)">readonly</xsl:if> global::System.Collections.Generic.List&lt;<xsl:value-of select="$type" />&gt; <xsl:value-of select="$field"/> = new global::System.Collections.Generic.List&lt;<xsl:value-of select="$type"/>&gt;();
    [<xsl:apply-templates select="." mode="checkDeprecated"/>global::ProtoBuf.ProtoMember(<xsl:value-of select="number"/>, Name=@"<xsl:value-of select="name"/>", DataFormat = global::ProtoBuf.DataFormat.<xsl:value-of select="$format"/><xsl:if test="options/packed='true'">, Options = global::ProtoBuf.MemberSerializationOptions.Packed</xsl:if>)]<!--
    --><xsl:if test="$optionDataContract">
    [global::System.Runtime.Serialization.DataMember(Name=@"<xsl:value-of select="name"/>", Order = <xsl:value-of select="number"/>, IsRequired = false)]
    </xsl:if><xsl:if test="$optionXml">
    [global::System.Xml.Serialization.XmlElement(@"<xsl:value-of select="name"/>", Order = <xsl:value-of select="number"/>)]
    </xsl:if>
    public global::System.Collections.Generic.List&lt;<xsl:value-of select="$type" />&gt; <xsl:call-template name="pascal"/>
    {
      get { return <xsl:value-of select="$field"/>; }<!--
      --><xsl:if test="$optionXml">
      set { <xsl:value-of select="$field"/> = value; }</xsl:if>
    }
  </xsl:template>

I've pulled out the specific parts for the private field and the setter:

private <xsl:if test="not($optionXml)">readonly</xsl:if> ...snip...

public ...snip...
{
  ...snip... 
  <!----><xsl:if test="$optionXml">
  set { <xsl:value-of select="$field"/> = value; }
  </xsl:if>
}

Notice the suspect conditions above for $optionXml. If you just remove those, the field is no longer readonly and the setter is properly generated.

So it then becomes: private ...snip...

public ...snip...
{
  ...snip... 
  set { <xsl:value-of select="$field"/> = value; }
}

Full 'fixed' template:

  <xsl:template match="FieldDescriptorProto[label='LABEL_REPEATED']">
    <xsl:variable name="type"><xsl:apply-templates select="." mode="type"/></xsl:variable>
    <xsl:variable name="format"><xsl:apply-templates select="." mode="format"/></xsl:variable>
    <xsl:variable name="field"><xsl:apply-templates select="." mode="field"/></xsl:variable>
    private global::System.Collections.Generic.List&lt;<xsl:value-of select="$type" />&gt; <xsl:value-of select="$field"/> = new global::System.Collections.Generic.List&lt;<xsl:value-of select="$type"/>&gt;();
    [<xsl:apply-templates select="." mode="checkDeprecated"/>global::ProtoBuf.ProtoMember(<xsl:value-of select="number"/>, Name=@"<xsl:value-of select="name"/>", DataFormat = global::ProtoBuf.DataFormat.<xsl:value-of select="$format"/><xsl:if test="options/packed='true'">, Options = global::ProtoBuf.MemberSerializationOptions.Packed</xsl:if>)]<!--
    --><xsl:if test="$optionDataContract">
    [global::System.Runtime.Serialization.DataMember(Name=@"<xsl:value-of select="name"/>", Order = <xsl:value-of select="number"/>, IsRequired = false)]
    </xsl:if><xsl:if test="$optionXml">
    [global::System.Xml.Serialization.XmlElement(@"<xsl:value-of select="name"/>", Order = <xsl:value-of select="number"/>)]
    </xsl:if>
    public global::System.Collections.Generic.List&lt;<xsl:value-of select="$type" />&gt; <xsl:call-template name="pascal"/>
    {
      get { return <xsl:value-of select="$field"/>; }
      set { <xsl:value-of select="$field"/> = value; }
    }
  </xsl:template>

I played with setting optionXml to false, but it didn't work and you may still want that option enabled anyway.


위와 마지막 fixed template을 보고 protogen.exe 폴더에 있는 csharp.xslt의 내용을 수정하면 될 것이다.

블로그 이미지

레몬도리 LemonDory

개발자의 이야기

댓글을 달아 주세요

HttpListener를 사용하여 개발 중에 서버포트로 연결이 불가하다는 메시지로 Exception이 떨어지는 현상이 발생하여 찾아본 명령어


명령 프롬프트(관리자 권한)를 열고 아래 명령어에 포트만 변경하여 실행하고 실행해보자


netsh http add urlacl url=http://*:8888/ user=Everyone listen=yes 


아래 참고 블로그를 링크 걸어놓는다.


참고 : http://www.windowcmc.com/q.php?q=netsh-http-kr-manual

블로그 이미지

레몬도리 LemonDory

개발자의 이야기

댓글을 달아 주세요