Sep 25, 2018

RePost: Naming convention - How to avoid calling everything with suffix "Manager"

https://stackoverflow.com/questions/1866794/naming-classes-how-to-avoid-calling-everything-a-whatevermanager?rq=1

Visul Studio Snippets - JavaScript revealing modul template

Here is snippet for revealing modul template explained among other here:

https://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript

For some reason only way to register is to create custom folder and use "Add" instead of "Import".
Bad part is that it doesn't get copied but just keeps reference to your folder.


<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>JS revealing module pattern</Title>
              <Shortcut>jsmodule</Shortcut>
        </Header>
        <Snippet>
            <Declarations>           
            <Object>
                <ID>Namespace</ID>
                <Type>object</Type>
                <ToolTip>Namespace</ToolTip>
                <Default>Namespace</Default>
            </Object>
            </Declarations>
            <Code Language="CSharp">
                <![CDATA[
                    "use strict";
                    var Snt = Snt || {};
                    Snt.$Namespace$ = Snt.$Namespace$ || {};
                    Snt.$Namespace$.ViewManager = (function () {
                        var options = null;
                       
                        function init(optionsParam) {
                            if (optionsParam) {
                                $$.extend(options, optionsParam);
                            }
                        }
                        return {
                            Init : init                       
                        };
                    })();
                ]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

Sep 24, 2018

Azure Cosmos Db tips (SQL)

https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-sql-query
Clause FROM refers to Collection of something.
If you deal with only one collection you can replace it with special keyword:

Root

; like this:

SELECT
Root.id,
Root.description,
Root.tags,
Root.foodGroup,
Root.manufacturerName,
Root.version
FROM Root
WHERE (Root.manufacturerName = "The Coca-Cola Company" AND Root.version > 0)


Here is good practical explanation in approaching the document design vs relational design.

https://docs.microsoft.com/en-us/azure/cosmos-db/modeling-data

When to embed and when not, or when to normalize and when keep stuff denormalized.

Sep 20, 2018

ASP.NET Core 2.1 - Download file (push)



[HttpGet]
        public async Task<IActionResult> DownloadAsync(int id)
        {
            var model = _baseRepository.Get<Literature>(id);
            var vModel = _mapper.Map<LiteratureViewModel>(model);
            if (model == null)
            {
                return Content(Resources.SharedResource.ErrorDownloadFileFileNotFound);
            }
            var memory = new MemoryStream();
            var fullName = _literatureService.GetFullPath(vModel);
            using (var stream = new FileStream(fullName, FileMode.Open))
            {
                await stream.CopyToAsync(memory);
            }
            memory.Position = 0;
            return File(memory, _literatureService.GetContentType(vModel), vModel.FileName);
        }


public string GetContentType(LiteratureViewModel model)
        {
            var types = GetMimeTypes();
            var ext = Path.GetExtension(model.FileName).ToLowerInvariant();
            return types[ext];
        }
        private Dictionary<string, string> GetMimeTypes()
        {
            return new Dictionary<string, string>
            {
                {".txt", "text/plain"},
                {".pdf", "application/pdf"},
                {".doc", "application/vnd.ms-word"},
                {".docx", "application/vnd.ms-word"},
                {".xls", "application/vnd.ms-excel"},
                {".xlsx", "application/vnd.openxmlformatsofficedocument.spreadsheetml.sheet"},
                {".png", "image/png"},
                {".jpg", "image/jpeg"},
                {".jpeg", "image/jpeg"},
                {".gif", "image/gif"},
                {".csv", "text/csv"}
            };
        } 

Sep 18, 2018

Visual Studio Snippet - IoC service reference

Standard pattern for IOC is to register you service interface through private field and constructor.
Here is Visual Studio snippet to help with that.
It's not fully auto but helps a lot to me.

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>IoCserviceReference</Title>
              <Shortcut>iocsrv</Shortcut>
        </Header>
        <Snippet>
            <Declarations>
            <Object>
                <ID>IService</ID>
                <Type>Interface</Type>
                <ToolTip>Service interface.</ToolTip>
                <Default>IService</Default>
            </Object>
            <Object>
                <ID>ServiceVar</ID>
                <Type>object</Type>
                <ToolTip>Service variable.</ToolTip>
                <Default>serviceVar</Default>
            </Object>
            </Declarations>
            <Code Language="CSharp">
                <![CDATA[
                    private readonly I$IService$ _$IService$ = null;
                    I$IService$ $IService$
                    _$IService$ = $IService$ ?? throw new ArgumentNullException(nameof($IService$));
                ]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

Sep 14, 2018

ASP.NET Core 2.1 - custom tag helper - render all hidden fields from model marked with Hidden attribute


Creating custom tag helper to inspect provided model
 public class StudentExamViewModel : ExamBaseViewModel
    {
        [HiddenInput]
        public int StudentId { get; set; }       
    }

 [HtmlTargetElement("hidden-fields")]
    public class HiddenFieldsTagHelper : TagHelper
    {
        [HtmlAttributeName("for-model")]
        public ModelExpression Model { get; set; }
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = "div";
            output.TagMode = TagMode.StartTagAndEndTag;
            var sb = new StringBuilder();         
            Model.ModelExplorer.ModelType.GetProperties()
                                 .Where(prop => Attribute.IsDefined(prop, typeof(HiddenInputAttribute)))
                                 .ToList()
                                 .ForEach(hp =>
                                 {
                                    var propVal = Model.Model.GetType().GetProperty(hp.Name).GetValue(Model.Model, null);
                                    sb.AppendFormat($"<input type='hidden' name='{hp.Name}' value='{propVal}' />");
                                 });
            output.PreContent.SetHtmlContent(sb.ToString());
        }
    }

Use in View:

 <hidden-fields for-model="@Model" />

Register in ViewImports.cshtml:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Web
Note that you need to reference root namespace!

Sep 12, 2018

ASP.NET Core 2.1 - Extending buildin taghelpers - select

Extend existing select tag helper:

namespace Web.Infrastructure.TagHelpers
{
    [HtmlTargetElement("examcategories", Attributes = ForAttributeName)]
    public class ExamCategorySelectTagHelper : SelectTagHelper
    {
        private const string ForAttributeName = "asp-for";
        private readonly IBaseRepository _baseRepository = null;
        public ExamCategorySelectTagHelper(
            IHtmlGenerator generator,
            IBaseRepository baseRepository
            ) : base(generator)
        {
            _baseRepository = baseRepository ?? throw new ArgumentNullException(nameof(baseRepository));
        }
       
        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            Items = new List<SelectListItem>()
            {
                new SelectListItem() { Text = "dummy", Value="dummy"  }
            };
            output.TagName = "select";
            await base.ProcessAsync(context, output);
        }
    }
}
Don't forget to fix your tagname to generate proper HTML select (bold above).

Register assembly with your taghelpers in _ViewImports.cshtml

Watch it! For some reason you MUST register complete assembly namespace. In my case it was:

@addTagHelper *, Web

This WON'T work:

@addTagHelper *, Web.Infrastructure.TagHelpers

Don't know why :(

Rebuild and you should have proper reference in Visual Studio autocomplete.

                <examcategories asp-for="ExamCategoryId" asp-items="ViewBag.Dummy" class="form-control"></examcategories>
Cool thing is that you can peek into production tag helper source code on GitHub: