├── .gitignore
├── .vs
└── config
│ └── applicationhost.config
├── Controllers
├── NotesController.cs
└── SystemController.cs
├── Data
├── NoteContext.cs
└── NoteRepository.cs
├── Infrastructure
└── NoCacheAttribute.cs
├── Interfaces
└── INoteRepository.cs
├── Model
├── Note.cs
├── NoteImage.cs
├── NoteParam.cs
└── Settings.cs
├── NotebookAppApi.csproj
├── NotebookAppApi.csproj.user
├── NotebookAppApi.sln
├── Program.cs
├── Properties
└── launchSettings.json
├── README.md
├── Startup.cs
├── appsettings.Development.json
└── appsettings.json
/.gitignore:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio.
3 | ################################################################################
4 |
5 | /bin/
6 | /obj/
7 | /.vs/
8 | /.vscode/
9 | /Backup
10 | /obj
11 | /UpgradeLog.htm
12 | .vs/config/applicationhost.config
13 | NotebookAppApi.csproj.user
14 |
--------------------------------------------------------------------------------
/.vs/config/applicationhost.config:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 |
806 |
807 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
819 |
820 |
821 |
822 |
823 |
824 |
825 |
826 |
827 |
828 |
829 |
830 |
831 |
832 |
833 |
834 |
835 |
836 |
837 |
838 |
841 |
842 |
843 |
844 |
845 |
846 |
847 |
848 |
849 |
850 |
851 |
852 |
853 |
856 |
857 |
858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 |
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
878 |
879 |
880 |
881 |
882 |
883 |
884 |
885 |
886 |
887 |
888 |
889 |
890 |
891 |
892 |
893 |
894 |
895 |
896 |
897 |
898 |
899 |
900 |
901 |
902 |
903 |
904 |
905 |
906 |
907 |
908 |
909 |
910 |
911 |
912 |
913 |
914 |
915 |
916 |
917 |
918 |
919 |
920 |
921 |
922 |
923 |
924 |
925 |
926 |
927 |
928 |
929 |
930 |
931 |
932 |
933 |
934 |
935 |
936 |
937 |
938 |
939 |
940 |
941 |
942 |
943 |
944 |
945 |
946 |
947 |
948 |
949 |
950 |
951 |
952 |
953 |
954 |
955 |
956 |
957 |
958 |
959 |
960 |
961 |
962 |
963 |
964 |
965 |
966 |
967 |
968 |
969 |
970 |
971 |
972 |
973 |
974 |
975 |
976 |
977 |
978 |
979 |
980 |
981 |
982 |
983 |
984 |
985 |
986 |
987 |
988 |
989 |
990 |
991 |
992 |
993 |
994 |
995 |
996 |
997 |
--------------------------------------------------------------------------------
/Controllers/NotesController.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Mvc;
3 | using NotebookAppApi.Interfaces;
4 | using NotebookAppApi.Model;
5 | using NotebookAppApi.Infrastructure;
6 | using System;
7 | using System.Collections.Generic;
8 |
9 | namespace NotebookAppApi.Controllers
10 | {
11 | [Produces("application/json")]
12 | [Route("api/[controller]")]
13 | public class NotesController : Controller
14 | {
15 | private readonly INoteRepository _noteRepository;
16 |
17 | public NotesController(INoteRepository noteRepository)
18 | {
19 | _noteRepository = noteRepository;
20 | }
21 |
22 | [NoCache]
23 | [HttpGet]
24 | public async Task> Get()
25 | {
26 | return await _noteRepository.GetAllNotes();
27 | }
28 |
29 | // GET api/notes/5
30 | [HttpGet("{id}")]
31 | public async Task Get(string id)
32 | {
33 | return await _noteRepository.GetNote(id) ?? new Note();
34 | }
35 |
36 | // GET api/notes/text/date/size
37 | // ex: http://localhost:53617/api/notes/Test/2018-01-01/10000
38 | [NoCache]
39 | [HttpGet(template: "{bodyText}/{updatedFrom}/{headerSizeLimit}")]
40 | public async Task> Get(string bodyText,
41 | DateTime updatedFrom,
42 | long headerSizeLimit)
43 | {
44 | return await _noteRepository.GetNote(bodyText, updatedFrom, headerSizeLimit)
45 | ?? new List();
46 | }
47 |
48 | // POST api/notes
49 | [HttpPost]
50 | public void Post([FromBody] NoteParam newNote)
51 | {
52 | _noteRepository.AddNote(new Note
53 | {
54 | Id = newNote.Id,
55 | Body = newNote.Body,
56 | UpdatedOn = DateTime.Now,
57 | UserId = newNote.UserId
58 | });
59 | }
60 |
61 | // PUT api/notes/5
62 | [HttpPut("{id}")]
63 | public void Put(string id, [FromBody]string value)
64 | {
65 | _noteRepository.UpdateNoteDocument(id, value);
66 | }
67 |
68 | // DELETE api/notes/23243423
69 | [HttpDelete("{id}")]
70 | public void Delete(string id)
71 | {
72 | _noteRepository.RemoveNote(id);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Controllers/SystemController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.AspNetCore.Mvc;
3 |
4 | using NotebookAppApi.Interfaces;
5 | using NotebookAppApi.Model;
6 |
7 | namespace NotebookAppApi.Controllers
8 | {
9 | [Route("api/[controller]")]
10 | public class SystemController : Controller
11 | {
12 | private readonly INoteRepository _noteRepository;
13 |
14 | public SystemController(INoteRepository noteRepository)
15 | {
16 | _noteRepository = noteRepository;
17 | }
18 |
19 | // Call an initialization - api/system/init
20 | [HttpGet("{setting}")]
21 | public string Get(string setting)
22 | {
23 | if (setting == "init")
24 | {
25 | _noteRepository.RemoveAllNotes();
26 | var name = _noteRepository.CreateIndex();
27 |
28 | _noteRepository.AddNote(new Note()
29 | {
30 | Id = "1",
31 | Body = "Test note 1",
32 | UpdatedOn = DateTime.Now,
33 | UserId = 1,
34 | HeaderImage = new NoteImage
35 | {
36 | ImageSize = 10,
37 | Url = "http://localhost/image1.png",
38 | ThumbnailUrl = "http://localhost/image1_small.png"
39 | }
40 | });
41 |
42 | _noteRepository.AddNote(new Note()
43 | {
44 | Id = "2",
45 | Body = "Test note 2",
46 | UpdatedOn = DateTime.Now,
47 | UserId = 1,
48 | HeaderImage = new NoteImage
49 | {
50 | ImageSize = 13,
51 | Url = "http://localhost/image2.png",
52 | ThumbnailUrl = "http://localhost/image2_small.png"
53 | }
54 | });
55 |
56 | _noteRepository.AddNote(new Note()
57 | {
58 | Id = "3",
59 | Body = "Test note 3",
60 | UpdatedOn = DateTime.Now,
61 | UserId = 1,
62 | HeaderImage = new NoteImage
63 | {
64 | ImageSize = 14,
65 | Url = "http://localhost/image3.png",
66 | ThumbnailUrl = "http://localhost/image3_small.png"
67 | }
68 | });
69 |
70 | _noteRepository.AddNote(new Note()
71 | {
72 | Id = "4",
73 | Body = "Test note 4",
74 | UpdatedOn = DateTime.Now,
75 | UserId = 1,
76 | HeaderImage = new NoteImage
77 | {
78 | ImageSize = 15,
79 | Url = "http://localhost/image4.png",
80 | ThumbnailUrl = "http://localhost/image4_small.png"
81 | }
82 | });
83 |
84 | return "Database NotesDb was created, and collection 'Notes' was filled with 4 sample items";
85 | }
86 |
87 | return "Unknown";
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Data/NoteContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Options;
2 | using MongoDB.Driver;
3 | using NotebookAppApi.Model;
4 |
5 | namespace NotebookAppApi.Data
6 | {
7 | public class NoteContext
8 | {
9 | private readonly IMongoDatabase _database = null;
10 |
11 | public NoteContext(IOptions settings)
12 | {
13 | var client = new MongoClient(settings.Value.ConnectionString);
14 | if (client != null)
15 | _database = client.GetDatabase(settings.Value.Database);
16 | }
17 |
18 | public IMongoCollection Notes
19 | {
20 | get
21 | {
22 | return _database.GetCollection("Note");
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Data/NoteRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using MongoDB.Bson;
3 | using MongoDB.Driver;
4 | using NotebookAppApi.Model;
5 | using System.Threading.Tasks;
6 | using NotebookAppApi.Interfaces;
7 | using System.Collections.Generic;
8 | using Microsoft.Extensions.Options;
9 |
10 | using MongoDB.Driver.Linq;
11 |
12 | namespace NotebookAppApi.Data
13 | {
14 | public class NoteRepository : INoteRepository
15 | {
16 | private readonly NoteContext _context = null;
17 |
18 | public NoteRepository(IOptions settings)
19 | {
20 | _context = new NoteContext(settings);
21 | }
22 |
23 | public async Task> GetAllNotes()
24 | {
25 | try
26 | {
27 | return await _context.Notes.Find(_ => true).ToListAsync();
28 | }
29 | catch (Exception ex)
30 | {
31 | // log or manage the exception
32 | throw ex;
33 | }
34 | }
35 |
36 | // query after Id or InternalId (BSonId value)
37 | //
38 | public async Task GetNote(string id)
39 | {
40 | try
41 | {
42 | ObjectId internalId = GetInternalId(id);
43 | return await _context.Notes
44 | .Find(note => note.Id == id || note.InternalId == internalId)
45 | .FirstOrDefaultAsync();
46 | }
47 | catch (Exception ex)
48 | {
49 | // log or manage the exception
50 | throw ex;
51 | }
52 | }
53 |
54 | // query after body text, updated time, and header image size
55 | //
56 | public async Task> GetNote(string bodyText, DateTime updatedFrom, long headerSizeLimit)
57 | {
58 | try
59 | {
60 | var query = _context.Notes.Find(note => note.Body.Contains(bodyText) &&
61 | note.UpdatedOn >= updatedFrom &&
62 | note.HeaderImage.ImageSize <= headerSizeLimit);
63 |
64 | return await query.ToListAsync();
65 | }
66 | catch (Exception ex)
67 | {
68 | // log or manage the exception
69 | throw ex;
70 | }
71 | }
72 |
73 | // Try to convert the Id to a BSonId value
74 | private ObjectId GetInternalId(string id)
75 | {
76 | if (!ObjectId.TryParse(id, out ObjectId internalId))
77 | internalId = ObjectId.Empty;
78 |
79 | return internalId;
80 | }
81 |
82 | public async Task AddNote(Note item)
83 | {
84 | try
85 | {
86 | await _context.Notes.InsertOneAsync(item);
87 | }
88 | catch (Exception ex)
89 | {
90 | // log or manage the exception
91 | throw ex;
92 | }
93 | }
94 |
95 | public async Task RemoveNote(string id)
96 | {
97 | try
98 | {
99 | DeleteResult actionResult = await _context.Notes.DeleteOneAsync(
100 | Builders.Filter.Eq("Id", id));
101 |
102 | return actionResult.IsAcknowledged
103 | && actionResult.DeletedCount > 0;
104 | }
105 | catch (Exception ex)
106 | {
107 | // log or manage the exception
108 | throw ex;
109 | }
110 | }
111 |
112 | public async Task UpdateNote(string id, string body)
113 | {
114 | var filter = Builders.Filter.Eq(s => s.Id, id);
115 | var update = Builders.Update
116 | .Set(s => s.Body, body)
117 | .CurrentDate(s => s.UpdatedOn);
118 |
119 | try
120 | {
121 | UpdateResult actionResult = await _context.Notes.UpdateOneAsync(filter, update);
122 |
123 | return actionResult.IsAcknowledged
124 | && actionResult.ModifiedCount > 0;
125 | }
126 | catch (Exception ex)
127 | {
128 | // log or manage the exception
129 | throw ex;
130 | }
131 | }
132 |
133 | public async Task UpdateNote(string id, Note item)
134 | {
135 | try
136 | {
137 | ReplaceOneResult actionResult = await _context.Notes
138 | .ReplaceOneAsync(n => n.Id.Equals(id)
139 | , item
140 | , new UpdateOptions { IsUpsert = true });
141 | return actionResult.IsAcknowledged
142 | && actionResult.ModifiedCount > 0;
143 | }
144 | catch (Exception ex)
145 | {
146 | // log or manage the exception
147 | throw ex;
148 | }
149 | }
150 |
151 | // Demo function - full document update
152 | public async Task UpdateNoteDocument(string id, string body)
153 | {
154 | var item = await GetNote(id) ?? new Note();
155 | item.Body = body;
156 | item.UpdatedOn = DateTime.Now;
157 |
158 | return await UpdateNote(id, item);
159 | }
160 |
161 | public async Task RemoveAllNotes()
162 | {
163 | try
164 | {
165 | DeleteResult actionResult = await _context.Notes.DeleteManyAsync(new BsonDocument());
166 |
167 | return actionResult.IsAcknowledged
168 | && actionResult.DeletedCount > 0;
169 | }
170 | catch (Exception ex)
171 | {
172 | // log or manage the exception
173 | throw ex;
174 | }
175 | }
176 |
177 | // it creates a sample compound index (first using UserId, and then Body)
178 | //
179 | // MongoDb automatically detects if the index already exists - in this case it just returns the index details
180 | public async Task CreateIndex()
181 | {
182 | try
183 | {
184 | IndexKeysDefinition keys = Builders
185 | .IndexKeys
186 | .Ascending(item => item.UserId)
187 | .Ascending(item => item.Body);
188 |
189 | return await _context.Notes
190 | .Indexes.CreateOneAsync(new CreateIndexModel(keys));
191 | }
192 | catch (Exception ex)
193 | {
194 | // log or manage the exception
195 | throw ex;
196 | }
197 | }
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/Infrastructure/NoCacheAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.AspNetCore.Mvc.Filters;
3 |
4 | namespace NotebookAppApi.Infrastructure
5 | {
6 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
7 | public sealed class NoCacheAttribute : ActionFilterAttribute
8 | {
9 | public override void OnResultExecuting(ResultExecutingContext context)
10 | {
11 | context.HttpContext.Response.Headers["Cache-Control"] = "no-cache, no-store, max-age=0";
12 | context.HttpContext.Response.Headers["Pragma"] = "no-cache";
13 | context.HttpContext.Response.Headers["Expires"] = "-1";
14 |
15 | base.OnResultExecuting(context);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Interfaces/INoteRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using NotebookAppApi.Model;
5 |
6 | namespace NotebookAppApi.Interfaces
7 | {
8 | public interface INoteRepository
9 | {
10 | Task> GetAllNotes();
11 |
12 | Task GetNote(string id);
13 |
14 | // query after multiple parameters
15 | Task> GetNote(string bodyText, DateTime updatedFrom, long headerSizeLimit);
16 |
17 | // add new note document
18 | Task AddNote(Note item);
19 |
20 | // remove a single document / note
21 | Task RemoveNote(string id);
22 |
23 | // update just a single document / note
24 | Task UpdateNote(string id, string body);
25 |
26 | // demo interface - full document update
27 | Task UpdateNoteDocument(string id, string body);
28 |
29 | // should be used with high cautious, only in relation with demo setup
30 | Task RemoveAllNotes();
31 |
32 | // creates a sample index
33 | Task CreateIndex();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Model/Note.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using MongoDB.Bson;
3 | using MongoDB.Bson.Serialization.Attributes;
4 |
5 | namespace NotebookAppApi.Model
6 | {
7 | public class Note
8 | {
9 | [BsonId]
10 | // standard BSonId generated by MongoDb
11 | public ObjectId InternalId { get; set; }
12 |
13 | // external Id, easier to reference: 1,2,3 or A, B, C etc.
14 | public string Id { get; set; }
15 |
16 | public string Body { get; set; } = string.Empty;
17 |
18 | [BsonDateTimeOptions]
19 | public DateTime UpdatedOn { get; set; } = DateTime.Now;
20 |
21 | public NoteImage HeaderImage { get; set; }
22 |
23 | public int UserId { get; set; } = 0;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Model/NoteImage.cs:
--------------------------------------------------------------------------------
1 | namespace NotebookAppApi.Model
2 | {
3 | public class NoteImage
4 | {
5 | public string Url { get; set; } = string.Empty;
6 | public string ThumbnailUrl { get; set; } = string.Empty;
7 | public long ImageSize { get; set; } = 0L;
8 | }
9 | }
--------------------------------------------------------------------------------
/Model/NoteParam.cs:
--------------------------------------------------------------------------------
1 | namespace NotebookAppApi.Model
2 | {
3 | public class NoteParam
4 | {
5 | public string Id { get; set; } = string.Empty;
6 | public string Body { get; set; } = string.Empty;
7 | public int UserId { get; set; } = 0;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Model/Settings.cs:
--------------------------------------------------------------------------------
1 | namespace NotebookAppApi.Model
2 | {
3 | public class Settings
4 | {
5 | public string ConnectionString;
6 | public string Database;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/NotebookAppApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/NotebookAppApi.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ProjectDebugger
5 |
6 |
7 | IIS Express
8 |
9 |
--------------------------------------------------------------------------------
/NotebookAppApi.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26730.12
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotebookAppApi", "NotebookAppApi.csproj", "{2C2FC4BF-2EEB-438C-8F91-67CA423FC08F}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {2C2FC4BF-2EEB-438C-8F91-67CA423FC08F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {2C2FC4BF-2EEB-438C-8F91-67CA423FC08F}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {2C2FC4BF-2EEB-438C-8F91-67CA423FC08F}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {2C2FC4BF-2EEB-438C-8F91-67CA423FC08F}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {D093D56B-E229-4700-8D2F-FFE6C66EFC0C}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore;
2 | using Microsoft.AspNetCore.Hosting;
3 |
4 | namespace NotebookAppApi
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | BuildWebHost(args).Run();
11 | }
12 |
13 | public static IWebHost BuildWebHost(string[] args) =>
14 | WebHost.CreateDefaultBuilder(args)
15 | .UseStartup()
16 | .Build();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:53617/",
7 | "sslPort": 0
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "launchUrl": "api/notes",
15 | "environmentVariables": {
16 | "ASPNETCORE_ENVIRONMENT": "Development"
17 | }
18 | },
19 | "NotebookAppApi": {
20 | "commandName": "Project",
21 | "launchBrowser": true,
22 | "launchUrl": "http://localhost:5000/api/notes",
23 | "environmentVariables": {
24 | "ASPNETCORE_ENVIRONMENT": "Development"
25 | }
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Example: Using MongoDB .NET Driver with .NET Core WebAPI
2 |
3 | Walkthrough blog post - [http://qappdesign.com/using-mongodb-with-net-core-webapi](http://qappdesign.com/using-mongodb-with-net-core-webapi)
4 |
5 | This is the first blog post, presenting the backend associated with a sample application: NotebookApp.
6 |
7 | It is a quick walkthrough on using .NET Core 2 to build a Web API layer using MongoDB .NET Driver version 2. All the calls to the database are asynchronous.
8 |
9 | #### Topics Covered
10 | - Technology stack
11 | - Configuration model
12 | - Options model
13 | - Dependency injection
14 | - MongoDb – Installation and configuration using MongoDB C# Driver v.2
15 | - Make a full ASP.NET WebApi project, connected async to MongoDB
16 | - Allowing Cross Domain Calls (CORS)
17 | - Update entire MongoDB documents
18 | - Exception management
19 |
20 | #### How to run it
21 | - Download or clone this project locally
22 | - Install the tools - see here more details: [http://qappdesign.com/using-mongodb-with-net-core-webapi](http://qappdesign.com/using-mongodb-with-net-core-webapi)
23 | - Run first the MongoDB server (details in the article)
24 | - Then in the console, within the current project folder, run the next two commands: `dotnet restore`, and then `dotnet run`
25 | - The ASP.NET Core WebAPI will run using IIS (default settings: http://localhost:5000)
26 |
--------------------------------------------------------------------------------
/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.Extensions.Configuration;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using NotebookAppApi.Interfaces;
6 | using NotebookAppApi.Data;
7 | using NotebookAppApi.Model;
8 |
9 | namespace NotebookAppApi
10 | {
11 | public class Startup
12 | {
13 | public Startup(IConfiguration configuration)
14 | {
15 | Configuration = configuration;
16 | }
17 |
18 | public IConfiguration Configuration { get; }
19 |
20 | // This method gets called by the runtime. Use this method to add services to the container.
21 | public void ConfigureServices(IServiceCollection services)
22 | {
23 | services.AddCors(options =>
24 | {
25 | options.AddPolicy("CorsPolicy",
26 | builder => builder.AllowAnyOrigin()
27 | .AllowAnyMethod()
28 | .AllowAnyHeader()
29 | .AllowCredentials());
30 | });
31 |
32 | services.AddMvc();
33 |
34 | services.Configure(options =>
35 | {
36 | options.ConnectionString = Configuration.GetSection("MongoConnection:ConnectionString").Value;
37 | options.Database = Configuration.GetSection("MongoConnection:Database").Value;
38 | });
39 |
40 | services.AddTransient();
41 | }
42 |
43 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
44 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
45 | {
46 | app.UseCors("CorsPolicy");
47 |
48 | if (env.IsDevelopment())
49 | {
50 | app.UseDeveloperExceptionPage();
51 | }
52 |
53 | app.UseMvc();
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Debug",
6 | "System": "Information",
7 | "Microsoft": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "MongoConnection": {
3 | "ConnectionString": "mongodb://admin:abc123!@localhost",
4 | "Database": "NotesDb"
5 | },
6 |
7 | "Logging": {
8 | "IncludeScopes": false,
9 | "Debug": {
10 | "LogLevel": {
11 | "Default": "Warning"
12 | }
13 | },
14 | "Console": {
15 | "LogLevel": {
16 | "Default": "Warning"
17 | }
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------