asp.net으로 rest api개발할 때 Swashbuckle.AspNetCore 패키지를 많이 사용할 것입니다.

그런데 기본 설정으로는 소스코드의 주석이 swagger주석으로 출력되지 않기 때문에 다음 설정을 해줘야합니다.

 

1. 프로젝스 설정 > 빌드 > 설명서 파일을 체크.

 

2. Program.cs 에 AddSwaggerGen 부분의 코드를 아래와 같은 형태로 변경

            builder.Services.AddSwaggerGen(options =>
            {
                // using System.Reflection;
                var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
            });

'C#' 카테고리의 다른 글

엑셀의 공분산 COVARIANCE.P, COVARIANCE.S 함수의 c#구현  (0) 2020.08.07
asp.net core 3.1, NLog 설정시 문제해결  (0) 2020.06.26
log4net.config 예제  (0) 2019.08.03
GDI+ Bitmap Rotaion  (0) 2019.02.19
WPF RichText에서 HTML 표시하기  (2) 2019.02.09

값 출력 비교를 위한 엑셀의 샘플 자료값입니다.

    class Program
    {
        static void Main(string[] args)
        {
            var x = new decimal[] { 20, 30, 40, 50, 60, 70 };
            var y = new decimal[] { 12.48M, 32.33M, 33.11M, 84.12M, 45.91M, 40.11M };

            var cp = CovarianceP(x, y);
            Console.WriteLine("Covariance Population : {0}", cp); //모집단 공분산


            var cs = CovarianceS(x, y);
            Console.WriteLine("Covariance Sample : {0}", cs); //표본집단 공분산

            Console.ReadLine();
        }

        /// <summary>
        /// 모집단 공분산 구하기
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        static decimal CovarianceP(decimal[] x, decimal[] y)
        {
            if (x.Length != y.Length)
                throw new ArgumentException("two parameters must be same length.");

            var avg_x = x.Average();
            var avg_y = y.Average();

            return x.Zip(y, (x1, y1) => (x1 - avg_x) * (y1 - avg_y)).Average();
        }

        /// <summary>
        /// 표본집단 공분산 구하기
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        static decimal CovarianceS(decimal[] x, decimal[] y)
        {
            if (x.Length != y.Length)
                throw new ArgumentException("two parameters must be same length.");

            var avg_x = x.Average();
            var avg_y = y.Average();

            return x.Zip(y, (x1, y1) => (x1 - avg_x) * (y1 - avg_y)).Sum() / (x.Length -1);
        }
    }

 

결과입니다.

double로 하실경우 소수점 마지막자리에 오차가 좀 발생합니다.

 

 

공분산에 대한 설명은 이분 블로그에서 너무나 친절하고 쉽게 설명이 되어 있습니다.

https://blog.naver.com/ikek21/220003173213

 

공분산(covariance)

공분산이 뭐에요? 란 질문에.. 난 당황했었다.. 다.. 당황하셨어요? 그리곤 재빨리 자리를 피했다.. 하지만...

blog.naver.com

 

배포환경은 리눅스 Centos7 였습니다.

윈도우 로컬 개발환경에서는 잘 기록되는 NLog가 리눅스 서버에 배포하면 잘 기록되지 않는 문제였습니다.

 

진입점소스는 아래와 같은 형태였었습니다. (네, 인터넷에서 검색해서 그냥 넣었습니다 ㅡㅡ)

        public static void Main(string[] args)
        {
            var config = new ConfigurationBuilder()
                            .SetBasePath(System.IO.Directory.GetCurrentDirectory())
                            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                            .Build();

            NLog.LogManager.Configuration = new NLogLoggingConfiguration(config.GetSection("NLog"));

            var host = CreateHostBuilder(args)
                .Build();
            
            host.Run();
        }

 

그리고 배포시에 사용하는  appsettings.Production.json 파일에 다음과 같이 설정하였습니다.

 

  {"NLog": {
    "variables": {
      "var_logdir": "/var/www/www.mydomain.com/log"
    },
    "targets": {
      "logfile": {
        "type": "File",
        "fileName": "${var_logdir}/nlog-${shortdate}.log"
      },
      "logconsole": {
        "type": "Console"
      }
    }
  }
 }

기본 개발환경에서는 var_logsdir 부분의 값은 "D:\Logs" 였구요..

 

첨에 왜 안되는지 이유를 모르고 좀 헤맸는데, 소스를 보면 간단히 확인되는 문제였습니다.!

 

위에 .AddJsonFile에서 기본적인 appsetting.json 만 해주었기 때문입니다.

(알아서 Production 등이 처리되는 줄... 착각했었네요..)

 

.AddJsonFile ... 부분 하단 라인에 아래와 같이 추가적으로 실행 환경에 맞는 설정을 추가해줘야합니다.

진입 함수에서 아래코드로 확인 가능합니다.

 

var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

 

=== 생략 ===

.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)

.AddEnvironmentVariables()

 

 

 

보통 Startup에서 저런 구성을 넣어주더군요...

 

하지만 굳이 env 불러오지 않고, 아래처럼 소스를 수정하여 해결을 보았습니다.

 

    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args)
                .Build();
            host.Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) => 
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration(ConfigConfiguration) //ConfigConfiguration 호출
                .UseNLog() //NLog 사용
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder
                    .ConfigureKestrel(serverOptions => {
                        serverOptions.Limits.MaxConcurrentConnections = 1000;
                        serverOptions.Limits.MaxConcurrentUpgradedConnections = 1000;
                        serverOptions.Limits.MaxRequestBodySize = 1024 * 1024 * 100;
                        serverOptions.Limits.MinRequestBodyDataRate = new MinDataRate(bytesPerSecond: 100,
                                gracePeriod: TimeSpan.FromSeconds(10));
                        serverOptions.Limits.MinResponseDataRate = new MinDataRate(bytesPerSecond: 100,
                                gracePeriod: TimeSpan.FromSeconds(10));                        
                        serverOptions.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2);
                        serverOptions.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(1);
                    })
                    .UseStartup<Startup>();
                });
        

        static void ConfigConfiguration(HostBuilderContext ctx, IConfigurationBuilder config)
        {            
            NLog.LogManager.Configuration = new NLogLoggingConfiguration(config.Build().GetSection("NLog"));      
        }
    }

 

Builder 구성부분에서 config를 받아 메소드를 수행할 수 있도록 했고.

해당 메소드에서 NLog설정을 셋팅하도록 했습니다.

 

이제 각 환경 Development, Staging, Production 따라 각기 다른 환경에 맞게 로그가 잘 기록이 되는군요.

D:\Logs\2019\20190803\LOG_A_20190803.txt 형식으로 작성이 된다.

 

<?xml version="1.0" encoding="utf-8" ?>

<log4net>

  <appender name="DebugAppender" type="log4net.Appender.DebugAppender" >

    <layout type="log4net.Layout.PatternLayout">

      <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />

    </layout>

  </appender>

  <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">   

    <file type="log4net.Util.PatternString" value="D:\Logs\%date{yyyy}\%date{yyyy}%date{MM}%date{dd}\LOG_" />

    <datePattern value="'A_'yyyyMMdd'.txt'" />

    <param name="AppendToFile" value="true" />

    <param name="rollingStyle" value="Date" />

    <staticLogFileName value="false" />

    <layout  type="log4net.Layout.PatternLayout">

      <param name="conversionPattern" value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />

    </layout>

  </appender>

  <root>

    <level value="ALL"/>

    <appender-ref ref="DebugAppender" />

    <appender-ref ref="RollingLogFileAppender" />

  </root>

</log4net>

    private Bitmap RotateBitmap(Bitmap bitmap, float angle)
    {
        int w, h, x, y;
        var dW = (double)bitmap.Width;
        var dH = (double)bitmap.Height;

        double degrees = Math.Abs(angle);
        if (degrees <= 90)
        {
            double radians = 0.0174532925 * degrees;
            double dSin = Math.Sin(radians);
            double dCos = Math.Cos(radians);
            w = (int)(dH * dSin + dW * dCos);
            h = (int)(dW * dSin + dH * dCos);
            x = (w - bitmap.Width) / 2;
            y = (h - bitmap.Height) / 2;
        }
        else
        {
            degrees -= 90;
            double radians = 0.0174532925 * degrees;
            double dSin = Math.Sin(radians);
            double dCos = Math.Cos(radians);
            w = (int)(dW * dSin + dH * dCos);
            h = (int)(dH * dSin + dW * dCos);
            x = (w - bitmap.Width) / 2;
            y = (h - bitmap.Height) / 2;
        }

        var rotateAtX = bitmap.Width / 2f;
        var rotateAtY = bitmap.Height / 2f;

        var bmpRet = new Bitmap(w, h);
        bmpRet.SetResolution(bitmap.HorizontalResolution, bitmap.VerticalResolution);
        using (var graphics = Graphics.FromImage(bmpRet))
        {
            graphics.Clear(Color.White);
            graphics.TranslateTransform(rotateAtX + x, rotateAtY + y);
            graphics.RotateTransform(angle);
            graphics.TranslateTransform(-rotateAtX - x, -rotateAtY - y);
            graphics.DrawImage(bitmap, new PointF(0 + x, 0 + y));
        }
        return bmpRet;
    }

https://stackoverflow.com/questions/5172906/rotating-graphics


 RichText에서 HTML을 표시할 수 있는 방법에 대해 설명해놓은 글입니다.

물론 샘플 소스도 같이 있습니다.

https://www.codeproject.com/Articles/1097390/Displaying-HTML-in-a-WPF-RichTextBox


소스를 다운로드해서 샘플을 켜보면 RichText에 TextBox의 Text로 바로 바인딩을 걸어놔서, HTML 문법오류가나면, 바로 프로그램이 죽습니다.

그래서 생성자에 바로 HTML을 입력하고 테스트해보았습니다.






핵심은  HtmlConverter에서 HTML 분석기를 만들어 HtmlToXamlConveter를 호출한다는 겁니다.

FlowDocument 를 만들어서 입력하게끔하네요. 


RTF문서 만들고, 입력내용에 대해 수정하기가 쉽지않은데...

HTML로 하니 간편한 듯합니다..

유용하네요.



MainWindow.xaml


<Window x:Class="RichTextBlockSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:local="clr-namespace:RichTextBlockSample"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="HTML TextBlock sample"
        Width="400"
        Height="300"
        mc:Ignorable="d">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <TextBox Name="TextBox"
                 Margin="10,0"
                 HorizontalAlignment="Stretch"
                 VerticalAlignment="Center"
                 Text=""
                 TextWrapping="Wrap" />
        <RichTextBox Grid.Row="1"
                     local:HtmlRichTextBoxBehavior.Text="{Binding ElementName=TextBox, Path=Text}"
                     IsDocumentEnabled="True"
                     IsReadOnly="True" />
        <!--
        <WebBrowser Grid.Row="2"
                    local:WebBrowserBehavior.Body="{Binding ElementName=TextBox, Path=Text}" />-->
    </Grid>
</Window>



MainWindows.xaml.cs

using System.Windows;
using System.Windows.Controls;

namespace RichTextBlockSample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
	{
		public MainWindow()
		{
			InitializeComponent();

            TextBox.Text = "<span style=\"color:red; font-size:20px; font-weight:bold\">hello</span>";
            TextBox.Text += "<span style=\"color:blue; font-size:20px; font-weight:bold; font-family:aria\">world</span>";
            TextBox.Text += "<span style=\"color:green; font-size:20px; font-weight:bold; font-family:nanumgothic\">안녕하세요</span>";
        }
	}
}


라이센스 : https://www.codeproject.com/info/cpol10.aspx 보니 소스 재배포가 가능해서 파일 첨부합니다.


RichTextBlockSample.zip



'C#' 카테고리의 다른 글

log4net.config 예제  (0) 2019.08.03
GDI+ Bitmap Rotaion  (0) 2019.02.19
Visual Studio Debug.WriteLine 표시가 안될때 대처 방안  (2) 2018.11.15
WPF, Template Select 하기  (0) 2018.05.29
WPF MVVM 샘플코드  (0) 2018.05.28

1. 빌드하는 모드가 Debug모드인지 확인할 것.


2. 도구 / 옵션 / 디버깅 / 일반에 출력 창의 모든 텍스트를 [직접실행]창으로 리다이렉션 체크해제 확인

(Menu > tools > options > debugging > General > Redirect all output window text to the immediate window (NOT Checked)






2. 프로젝트 설정 페이지에서 빌드, 설정은 빌드, DEBUG 상수 정의, TRACE 상수 정의 확인 

(Project Properties > Build > Define DEBUG constant / Defile TRACE constatnt are all checked.




3. 출력 창에서 마우스 오른쪽 버튼 눌러 프로그램 출력 체크 확인 (이걸 몰라서 헤멨다 아오..)




4. 기타 App.config 에 이런거 있어도 안되고.

  <system.diagnostics>

    <trace>

      <listeners>

        <!-- This next line is the troublemaker. If it is there delete it-->

        <clear/>

      </listeners>

    </trace>

  </system.diagnostics>





'C#' 카테고리의 다른 글

GDI+ Bitmap Rotaion  (0) 2019.02.19
WPF RichText에서 HTML 표시하기  (2) 2019.02.09
WPF, Template Select 하기  (0) 2018.05.29
WPF MVVM 샘플코드  (0) 2018.05.28
doxygen 설치 및 설정  (0) 2018.05.14




C# WPF, 지난번 포스트 소스에 연결됩니다.

상황에 따라, 표시되는 템플릿이 자동으로 지정되게끔 만들 수 있네요.


SubjectSelectDataTemplate.cs

using System.Windows;

using System.Windows.Controls;

 

namespace WPF_MVVM_SAMPLE01

{

    public class SubjectSelectDataTemplate : DataTemplateSelector

    {

        public override DataTemplate SelectTemplate(object item, DependencyObject container)

        {

            Score score = item as Score;

            FrameworkElement el = container as FrameworkElement;

            return (DataTemplate)el.FindResource(score.SCORE > 60 ? "DataTemplate3" : "DataTemplate4");

        }

    }

}



TemplateSelectWindow.xaml

 

<Window x:Class="WpfApp1.TemplateSelectWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"       

        xmlns:local="clr-namespace:WPF_MVVM_SAMPLE01"

        mc:Ignorable="d"

        Title="TemplateSelectWindow" Height="450" Width="800">

    <Window.DataContext>

        <local:ItemViewModel></local:ItemViewModel>

    </Window.DataContext>

    <Window.Resources>

        <local:SubjectSelectDataTemplate x:Key="SubjectSelectDataTemplate"></local:SubjectSelectDataTemplate>

    </Window.Resources>

    <DockPanel>

        <ListBox ItemsSource="{Binding Items}" ItemTemplateSelector="{StaticResource SubjectSelectDataTemplate}" ></ListBox>

    </DockPanel>

</Window>



Dictionary1.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

                    xmlns:local="clr-namespace:WPF_MVVM_SAMPLE01">

    <DataTemplate x:Key="DataTemplate1">

        <TextBlock Text="{Binding SUBJECT}"></TextBlock>

    </DataTemplate>

    <DataTemplate x:Key="DataTemplate2">

        <Grid >

            <Rectangle HorizontalAlignment="Left" Height="30" Width="{Binding SCORE}" StrokeThickness="1" Fill="Red"></Rectangle>

            <TextBlock Text="{Binding SCORE}"></TextBlock>

        </Grid>

    </DataTemplate>

    <DataTemplate x:Key="DataTemplate3">

        <Grid>

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="150"></ColumnDefinition>

                <ColumnDefinition Width="150"></ColumnDefinition>

            </Grid.ColumnDefinitions>

            <TextBlock Grid.Column="0" Text="{Binding SUBJECT}"></TextBlock>

            <Rectangle Grid.Column="1" HorizontalAlignment="Left" Height="30" Width="{Binding SCORE}" StrokeThickness="1" Fill="Red"></Rectangle>

            <TextBlock Grid.Column="1" Text="{Binding SCORE}"></TextBlock>   

        </Grid>

    </DataTemplate>

    <DataTemplate x:Key="DataTemplate4">

        <Grid>

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="150"></ColumnDefinition>

                <ColumnDefinition Width="150"></ColumnDefinition>

            </Grid.ColumnDefinitions>

            <TextBlock Grid.Column="1" Text="{Binding SUBJECT}"></TextBlock>

            <Rectangle Grid.Column="0" HorizontalAlignment="Left" Height="30" Width="{Binding SCORE}" StrokeThickness="1" Fill="Red"></Rectangle>

            <TextBlock Grid.Column="0" Text="{Binding SCORE}"></TextBlock>

        </Grid>

    </DataTemplate>

 

</ResourceDictionary>



소스는 여기 올려뒀습니다. https://github.com/erith/WPF_SAMPLES/tree/master/WpfApp1

+ Recent posts