WeddingThankYou
1.0.0.0
결혼식 이후 감사 인사와 사진, 계좌 안내, 연락처를 모바일 페이지로 전달하는 감사장 서비스입니다.
Toggle main menu visibility
로딩중...
검색중...
일치하는것 없음
CsvGuestbookStorage.cs
이 파일의 문서화 페이지로 가기
1
using
System;
2
using
System.Collections.Generic;
3
using
System.Globalization;
4
using
System.IO;
5
using
System.Text;
6
using
System.Threading;
7
using
System.Threading.Tasks;
8
using
Microsoft.Extensions.Hosting;
9
using
WeddingThankYou.Models
;
10
11
namespace
WeddingThankYou.Services
12
{
21
public
sealed
class
CsvGuestbookStorage
:
IGuestbookStorage
22
{
31
private
readonly
string
_dataDir
;
40
private
static
readonly SemaphoreSlim
_gate
=
new
(1, 1);
41
58
public
CsvGuestbookStorage
(IHostEnvironment env)
59
{
60
_dataDir
= Path.Combine(env.ContentRootPath,
"App_Data"
,
"Guestbook"
);
61
Directory.CreateDirectory(
_dataDir
);
62
}
63
88
private
string
CsvPath
(
string
slug) =>
89
Path.Combine(
_dataDir
, $
"{Sanitize(slug)}.csv"
);
90
115
private
static
string
Sanitize
(
string
slug) =>
116
string
.Concat((slug ??
string
.Empty).ToLowerInvariant().Split(Path.GetInvalidFileNameChars()));
117
150
public
async Task<IReadOnlyList<GuestbookEntry>>
LoadAsync
(
string
slug, CancellationToken ct =
default
)
151
{
152
var csvPath =
CsvPath
(slug);
153
await
_gate
.WaitAsync(ct).ConfigureAwait(
false
);
154
try
155
{
156
var result =
new
List<GuestbookEntry>();
157
if
(!File.Exists(csvPath))
return
result;
158
159
using
var fs =
new
FileStream(csvPath, FileMode.Open, FileAccess.Read, FileShare.Read);
160
using
var sr =
new
StreamReader(fs, Encoding.UTF8);
161
string
? line;
162
163
// 헤더 지원: 첫 줄이 헤더 같으면 스킵
164
bool
first =
true
;
165
while
((line = await sr.ReadLineAsync().ConfigureAwait(
false
)) !=
null
)
166
{
167
ct.ThrowIfCancellationRequested();
168
if
(
string
.IsNullOrWhiteSpace(line))
continue
;
169
170
if
(first &&
IsHeader
(line)) { first =
false
;
continue
; }
171
first =
false
;
172
173
var f =
ParseCsvLine
(line);
174
if
(f.Count < 4)
continue
;
175
176
if
(!DateTime.TryParseExact(f[3],
"yyyy-MM-dd HH:mm:ss"
,
177
CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var when))
178
when = DateTime.Now;
179
180
result.Add(
new
GuestbookEntry
181
{
182
Name = f[0],
183
Contact = f[1],
184
Message = f[2],
185
CreatedLocal = when
186
});
187
}
188
return
result;
189
}
190
finally
191
{
192
_gate
.Release();
193
}
194
}
195
236
public
async Task
SaveAsync
(
string
slug, IReadOnlyList<GuestbookEntry> entries, CancellationToken ct =
default
)
237
{
238
var csvPath =
CsvPath
(slug);
239
await
_gate
.WaitAsync(ct).ConfigureAwait(
false
);
240
try
241
{
242
var tmp = csvPath +
".tmp"
;
243
using
(var fs =
new
FileStream(tmp, FileMode.Create, FileAccess.Write, FileShare.None))
244
using
(var sw =
new
StreamWriter(fs,
new
UTF8Encoding(encoderShouldEmitUTF8Identifier:
false
)))
245
{
246
// 헤더 작성
247
await sw.WriteLineAsync(
"Name,Contact,Message,CreatedLocal"
).ConfigureAwait(
false
);
248
249
foreach
(var e
in
entries)
250
{
251
ct.ThrowIfCancellationRequested();
252
var line =
string
.Join(
","
,
253
EscapeCsv
(e.Name),
254
EscapeCsv
(e.Contact),
255
EscapeCsv
(e.Message),
256
EscapeCsv
(e.CreatedLocal.ToString(
"yyyy-MM-dd HH:mm:ss"
)));
257
await sw.WriteLineAsync(line).ConfigureAwait(
false
);
258
}
259
}
260
261
File.Copy(tmp, csvPath, overwrite:
true
);
262
File.Delete(tmp);
263
}
264
finally
265
{
266
_gate
.Release();
267
}
268
}
269
294
private
static
bool
IsHeader
(
string
line)
295
{
296
var l = line.Trim().ToLowerInvariant();
297
return
l.StartsWith(
"name,contact,message,createdlocal"
);
298
}
299
324
private
static
string
EscapeCsv
(
string
value)
325
{
326
value ??=
string
.Empty;
327
bool
needQuote = value.Contains(
','
) || value.Contains(
'"'
) || value.Contains(
'\n'
) || value.Contains(
'\r'
);
328
if
(!needQuote)
return
value;
329
return
$
"\"{value.Replace("
\
""
,
"\"\""
)}\
""
;
330
}
331
356
private
static
List<string>
ParseCsvLine
(
string
line)
357
{
358
var list =
new
List<string>();
359
if
(
string
.IsNullOrEmpty(line))
return
list;
360
361
var sb =
new
StringBuilder();
362
bool
inQuotes =
false
;
363
364
for
(
int
i = 0; i < line.Length; i++)
365
{
366
var ch = line[i];
367
if
(inQuotes)
368
{
369
if
(ch ==
'"'
)
370
{
371
if
(i + 1 < line.Length && line[i + 1] ==
'"'
)
372
{
373
sb.Append(
'"'
); i++;
// "" -> "
374
}
375
else
inQuotes =
false
;
376
}
377
else
sb.Append(ch);
378
}
379
else
380
{
381
if
(ch ==
','
) { list.Add(sb.ToString()); sb.Clear(); }
382
else
if
(ch ==
'"'
) inQuotes =
true
;
383
else
sb.Append(ch);
384
}
385
}
386
list.Add(sb.ToString());
387
return
list;
388
}
389
}
390
}
WeddingThankYou.Models
Definition
AccountInfo.cs:1
WeddingThankYou.Services
Definition
CsvGuestbookStorage.cs:12
WeddingThankYou.Models.GuestbookEntry
Definition
GuestbookEntry.cs:14
WeddingThankYou.Services.CsvGuestbookStorage.CsvPath
string CsvPath(string slug)
Definition
CsvGuestbookStorage.cs:88
WeddingThankYou.Services.CsvGuestbookStorage.EscapeCsv
static string EscapeCsv(string value)
Definition
CsvGuestbookStorage.cs:324
WeddingThankYou.Services.CsvGuestbookStorage.SaveAsync
async Task SaveAsync(string slug, IReadOnlyList< GuestbookEntry > entries, CancellationToken ct=default)
Definition
CsvGuestbookStorage.cs:236
WeddingThankYou.Services.CsvGuestbookStorage.LoadAsync
async Task< IReadOnlyList< GuestbookEntry > > LoadAsync(string slug, CancellationToken ct=default)
Definition
CsvGuestbookStorage.cs:150
WeddingThankYou.Services.CsvGuestbookStorage.Sanitize
static string Sanitize(string slug)
Definition
CsvGuestbookStorage.cs:115
WeddingThankYou.Services.CsvGuestbookStorage._dataDir
readonly string _dataDir
Definition
CsvGuestbookStorage.cs:31
WeddingThankYou.Services.CsvGuestbookStorage.ParseCsvLine
static List< string > ParseCsvLine(string line)
Definition
CsvGuestbookStorage.cs:356
WeddingThankYou.Services.CsvGuestbookStorage._gate
static readonly SemaphoreSlim _gate
Definition
CsvGuestbookStorage.cs:40
WeddingThankYou.Services.CsvGuestbookStorage.IsHeader
static bool IsHeader(string line)
Definition
CsvGuestbookStorage.cs:294
WeddingThankYou.Services.CsvGuestbookStorage.CsvGuestbookStorage
CsvGuestbookStorage(IHostEnvironment env)
Definition
CsvGuestbookStorage.cs:58
WeddingThankYou.Services.IGuestbookStorage
Definition
IGuestbookStorage.cs:17
Services
CsvGuestbookStorage.cs
다음에 의해 생성됨 :
1.17.0