Managing the Scope of a TagHelper - asp.net-core

Reading and learning about TagHelpers from a book so I wrote and used a TagHelper.
Writing it:
public class ButtonTagHelper: TagHelper
{
public string BsButtonColor { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.SetAttribute("class", $"btn btn-{BsButtonColor}");
}
}
and then using it in Razor like this:
<button bs-button-color="danger" type="submit">ADD</button>
OK I learned that much. Now in the next section about scopes it is saying:
which confuses me and I don't understand it. WHY? In my code above I didn't say apply it to all buttons. Where did that get from?
My understanding was that it looks at bs-button-color so if another button declaration in Razor doesn't have that, why would it be a problem?

OK went back to start of the chapter and read it again. Here is the convention I had missed reading it in round one:
The NAME of the TagHelper combines the name of the element it transforms followed by the word TagHelper.
and in my example the class is called ButtonTagHelper so it means it wants to apply it to BUTTONS

Related

ChildTag appears outside parentTag in TagHelper

I have Parent and Child TagHelper.. I have set attribute "parentTag" for Child Tag and yet it displays outside that parent Tag. How to restrict it from appearing outside parent Tag
[HtmlTargetElement("TestParent")]
public class Parent: TagHelper{
}
[HtmlTargetElement("TestChild",ParentTag = "TestParent")]
public class Child : TagHelper
{
}
What it need is that "TestChild" should not appear outside "TestParent"
For example:
<TestChild value=2></TestChild>
Above code must throw error or should not be shown in intellisense as it not enclosed by parent Tag "Testparent"
I tried to recreate your scenario with parent tag helper
[HtmlTargetElement("TestParent")]
public class ParentTagHelper : TagHelper
{
}
and a child tag helper:
[HtmlTargetElement("TestChild", ParentTag = "TestParent")]
public class ChildTagHelper : TagHelper
{
public int Value { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Content.SetContent(Value.ToString());
}
}
I added those two in _ViewImports.cshtml, then build the project. Then i called the tag helpers in a view:
<TestParent>
<TestChild value="101"></TestChild>
</TestParent>
<TestChild value="202"></TestChild>
I saw expected IntelliSense on first tag and didn't see one on the other one:
Finally, I executed the web app on ASP.NET Core 2.2. The HTML code of resulted page was:
<TestParent>
<TestChild>101</TestChild>
</TestParent>
<TestChild value="202"></TestChild>
It looks perfectly fine. Just as expected. The first tag was processed, the second one wasn't.
Conclusion
It looks like you had other problems aside from those described in original question. Most likely the problem wasn't in the sole tag helpers functionality and their restrictions on parent tags.

Support aliased arguments in get requests for web api

Background
I have a web api project which uses complex types for GET requests, here is an example of a controller method, and its associated complex type
[RoutePrefix("api")]
public class MyController : ApiController
{
[Route("Something")]
public IHttpActionResult GetSomething([FromUri]RequestObject request)
{
// do something to get "data"
return Ok(data);
}
}
// elsewhere
public class RequestObject
{
[Required]
public string SomeValue{get;set;}
}
This works with a url such as http://domain.com/api/Something?SomeValue=foo.
I would like to use alias' for these parameters, for which I will do some complex stuff (once I have this working) but effectively I have defined an attribute AliasAttribute.
[AttributeUsage(AttributeTargets.Property,AllowMultiple=true)]
public class AliasAttribute : Attribute
{
public string ParameterName { get; private set; }
public AliasAttribute(string parameterName)
{
this.ParameterName = parameterName;
}
}
Which I would like to adorn onto my request model like so:
// elsewhere
public class RequestObject
{
[Required,Alias("val")]
public string SomeValue{get;set;}
}
Allowing my url to shorten to http://domain.com/api/Something?val=foo. This is a contrived and simplified example, but hopefully demonstrates the background.
Problem
ModelBinding in web api has become very complex compared to Mvc model binding. I am getting twisted up between IModelBinder, IValueProvider, HttpParameterBinding et al.
I would like an example of where I should hook in to the model binding to allow me to write the value to my model from the querystring - note that I only use this aliasing behaviour when the route uses the FromUri attribute (see MyController.GetSomething above).
Question title: Support aliased arguments in get requests for web api. I think you are re-inventing a wheel here AliasAttribute , and have not given a really good reason why you don't want to use community ways of doing this.
I have done something similar with Newtonsoft.Json serializer. But if you want something ootb I'd have to google around.
public class RequestObject
{
[Required]
[JsonProperty("vla")]
public string SomeValue{get;set;}
}
Example SO that uses it: .Net NewtonSoft Json Deserialize map to a different property name
Here is a more agnostic way to do it.
[DataContract]
public class RequestObject
{
[DataMember(Name="val", IsRequired=true)]
public string SomeValue{get;set;}
}

Using Test Doubles with DbEntityEntry and DbPropertyEntry

I am using the new Test Doubles in EF6 as outlined here from MSDN . VS2013 with Moq & nUnit.
All was good until I had to do something like this:
var myFoo = context.Foos.Find(id);
and then:
myFoo.Name = "Bar";
and then :
context.Entry(myFoo).Property("Name").IsModified = true;
At this point is where I get an error:
Additional information: Member 'IsModified' cannot be called for
property 'Name' because the entity of type
'Foo' does not exist in the context. To add an
entity to the context call the Add or Attach method of
DbSet.
Although, When I examine the 'Foos' in the context with an AddWatch I can see all items I Add'ed before running the test. So they are there.
I have created the FakeDbSet (or TestDbSet) from the article. I am putting each FakeDbSet in the FakeContext at the constructor where each one gets initialized. Like this:
Foos = new FakeDbSet<Foo>();
My question is, is it possible to work with the FakeDbSet and the FakeContext with the test doubles scenario in such a way to have access to DbEntityEntry and DBPropertyEntry from the test double? Thanks!
I can see all items I Add'ed before running the test. So they are there.
Effectively, you've only added items to an ObservableCollection. The context.Entry method reaches much deeper than that. It requires a change tracker to be actively involved in adding, modifying and removing entities. If you want to mock this change tracker, the ObjectStateManager (ignoring the fact that it's not designed to be mocked at all), good luck! It's got over 4000 lines of code.
Frankly, I don't understand all these blogs and articles about mocking EF. Only the numerous differences between LINQ to objects and LINQ to entites should be enough to discourage it. These mock contexts and DbSets build an entirely new universe that's a source of bugs in itself. I've decided to do integrations test only when and wherever EF is involved in my code. A working end-to-end test gives me a solid feeling that things are OK. A unit test (faking EF) doesn't. (Others do, don't get me wrong).
But let's assume you'd still like to venture into mocking DbContext.Entry<T>. Too bad, impossible.
The method is not virtual
It returns a DbEntityEntry<T>, a class with an internal constructor, that is a wrapper around an InternalEntityEntry, which is an internal class. And, by the way, DbEntityEntry doesn't implement an interface.
So, to answer your question
is it possible to (...) have access to DbEntityEntry and DBPropertyEntry from the test double?
No, EF's mocking hooks are only very superficial, you'll never even come close to how EF really works.
Just abstract it. If you are working against an interface, when creating your own doubles, put the modified stuff in a seperate method. My interface and implementation (generated by EF, but I altered the template) look like this:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Model
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public interface IOmt
{
DbSet<DatabaseOmtObjectWhatever> DatabaseOmtObjectWhatever { get; set; }
int SaveChanges();
void SetModified(object entity);
void SetAdded(object entity);
}
public partial class Omt : DbContext, IOmt
{
public Omt()
: base("name=Omt")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<DatabaseOmtObjectWhatever> DatabaseOmtObjectWhatever { get; set; }
public void SetModified(object entity)
{
Entry(entity).State = EntityState.Modified;
}
public void SetAdded(object entity)
{
Entry(entity).State = EntityState.Added;
}
}
}

MVC 4 is overwriting specific Action-Parameters

MVC 4 does present me some strange behaviour at the moment.
Imagine the following Code:
TestController.cs
public class TestController : Controller
{
public ActionResult Index(Function function, string action)
{
return View();
}
public class Function
{
public string Action { get; set; }
}
}
It seems, that when I call the URL directly through the browser (localhost:PORT/Test), the Action-Property gets automatically filled with "Index".
If the Action would be named "MySuperDuperActionWhichGetsInvokedQuiteOften", exactly this Methodname would be in the property.
Can somebody explain what MVC is doing here?
The Problem is, that I of course want to fill that stuff myself, for example through an AJAX-Query. But if MVC is filling in this property all by itself, this breaks some behaviour.
I could, of course, just rename my property and it would be working, but it would still be quite interesting what's going on.
EDIT
I would understand it that my second parameter, string action, get's filled with the method-name. But why on earth would MVC bind any property/parameter that is named the same to the request-value of it?
It is problem with default model binder. It "maps" request fields to properties in your class. There is an article of MSDN describing how does it works but to simply this situation the code will be like this:
Action = Request["action"] //where of course Request["action"] equals to name of your action

fluent nhibernate polymorphism. how to check for type of class

I have an Icon which has a Content (one to one) relationship.
public class Icon
{
public virtual Content Content {get; set;}
}
By default, it is lazy loaded which is what I want.
However, at some point in the code, I need to check what kind of Content is, Content being polymorphic, something like
if(icon.Content is TextContent)
{
...
}
Icon is part of another association and it is automatically obtained by the NHibernate, I do not get it manually.
What is the recommended way of checking for the actual type in this situation?
I can have a specific property like ContentType which will be an enum in order to identify the actual content type, but I am looking to know if there's a different way.
If you want to do that kind of check, you have to remove the proxy from the property.
There is a few ways to do it:
If you have access to the session call:
session.PersistenceContext.Unproxy(icon.Content);
Implement a virtual method (in a base class if possible) that forces the removal of the proxy by returning the instance with the proper type.
public virtual U As<U>() where U : YourType {
return this as U;
}
Disable the lazy initialization of the property.
This is very similar to another recent question.
To add to csanchez's list, a fourth method is to add a Self property to the Content base class that returns the un-proxied type:
public virtual void Self
{
get { return this; }
}
And a fifth method is to use 'lazy="no-proxy"` in the mapping as described on Ayende's blog.
Thanks for the suggestions but meanwhile I found an interesting solution, better I think.
Using the Visitor pattern, I can define an IconContent visitor and pass an Action to be executed to it.
For example, suppose there is a TextContent and an ImageContent, it will be something like this:
IconContentVisitor.Func(()=> { Console.WriteLine("this is TextContent"; }, ()=> { Console.WriteLine("this is ImageContent"));
Idea came from here: http://mookid.dk/oncode/archives/991