How to follow/debug html creation in ASP.net - c#

I'm trying to find out where an extra div is inserted and how I would go about removing it.
In our Index.cshtml file we have this:
<div id="an-id">
#Html.DisplayFor(m => m.BottomArticleListContentArea, new { ViewName = "_ArticleListBlockNoHeader" })
</div>
And in our _ArticleListBlockNoHeader.cshtml view the code looks like this:
#if (Model != null)
{
for (int i = 0; i < Model.Items.Count; i++)
{
var article = Model.Items[i];
<div class="item" data-articleid="#article.ArticleId">
Item #article.ArticleId
</div>
}
}
BottomArticleListContentArea is a ContentArea and is handled by this DisplayTemplate:
#model ContentArea
#if (Model != null)
{
Html.RenderContentArea(Model);
}
As you can see, it doesn't really do anything except check if it's null. Oh... Maybe it does more things!
When I look at the generated html it looks like this:
<div id="an-id">
<div><div>
<div class="item" data-articleid="1">Item 1</div>
<div class="item" data-articleid="2">Item 2</div>
<div class="item" data-articleid="3">Item 3</div>
<div class="item" data-articleid="4">Item 4</div>
<div class="item" data-articleid="5">Item 5</div>
</div></div>
</div>
Notice how on row 2 and 9 there is two divs (<div><div> and </div></div>) that are not in the code I just shared above.
My hypothesis is now that these two divs might be added by some extension method somewhere or some handler or something else. I'm not familiar with the entire codebase and I'm fairly new with ASP.net so my knowledge of the insertion points in ASP.net is very limited.
Where could these two divs come from? And how can I start looking for them?
If something is missing in the question, please let me know, tried to be brief so that it would be easier to read and understand 😊
Thanks in advance!
Edit:
Made a mistake while cleaning the code, added back so that the result is what's generated by the code.
The HTML results above is what is returned and captured using fiddler. No JS has started running while the DOM is recorded.
Added the display template used.

This is the current solution that I have right now and I'm going to try out for a while:
(highly EPiServer specific)
Instead of letting it be rendered using RenderContentArea we're taking control over it and creating it the "raw" way with RenderContentData
foreach (var content in Model.FilteredItems)
{
Html.RenderContentData(content.GetContent(), false, Model.Tag);
}
This gets rid of all the extra divs and make it behave just the way we want it, just the way it seen when we read the code.
Yes, with this we're also loosing the ability to edit the page directly in epi visually. But that's something we need to look into later, for now, it works and I'm happy.
I also wrote this extended version that lets me choose if I want to skip the wrappers or not like this (notice DisableWrapper = true)
#Html.DisplayFor(m => m.ContentArea, new { DisableWrapper = true, ViewName = "_ArticleList" })
That can be done if I instead change the first code snippet to this:
var disableWrapper = Html.ViewContext.ViewData["DisableWrapper"] as bool?;
if (disableWrapper.GetValueOrDefault())
{
foreach (var content in Model.FilteredItems)
{
Html.RenderContentData(content.GetContent(), false, Model.Tag);
}
}
else
{
Html.RenderContentArea(Model);
}
This works and seems to produce the results I'm looking for. As stated previously, I haven't worked in this field for that long so if there's any suggestions or tips, I'd love to hear that and be able to improve my solution both here and in the project.
Thanks for the helpful comments that made me finally arrive at this solution!

Related

Trying to extract elements from a List<model> and display in Blazor razor component

I am brand new to Blazor Server, coming from a background in ASP.NET Webforms. I have a database that stores questions and answers for an employee safety test, and Im trying to display the test questions programatically in the HTML section of my page. When debugging, I get an Index Out of Range error.
Related Code:
#code {
private List<IForkLiftPerfTestContentModel> testquestion = new List<IForkLiftPerfTestContentModel>();
protected override async Task OnInitializedAsync()
{
testquestion = await testService.GetTestQuestions();
}
When I debug testquestion, it displays data properly as shown:
When I try to display an element by zero-based index, I get Index out of Range, although Intellisense doesnt complain about my code:
<td>
#testquestion[0].Topic
</td>
Clearly Im missing something, but again I am learning Blazor. Any help is appreciated!
When your blazor page will render first time, it will not yet have awaited your async operation, it will re-render once that operation is done.
Meaning on first render your testquestion will be empty - that's why you have Index Out Of Range, so you need to handle it, say for example "if testquestion is empty - display loading"
Thanks #Nikita! That was perfect!
I wrapped the Edit Form in an if/else like this:
#if (testquestion.Count == 0)
{
<h4>Test Loading...</h4>
}
else
{ <Editform>.....</EditForm>

How to find element - SAP NetWeaver

I'm using SAP NetWeaver (SAP WEB UI) and found it difficult to automate with selenium.
I can say that a big amount of objects' Id's\Names are actually being changed from one-page reloading to another.
So I have tried to use _webDriver.FIndElement(By.Xpath(//*[contains(#id,'foo')]));
But the element cannot be found. While this (find an element by XPath) can work on one object, it won't work for a different one. very frustrating.
It might be that either I'm doing something wrong or the object rendered is problematic.
This is an example for an HTML object :
<input id="grid#28.115#7,1#if" ct="I" lsdata="{0:'grid\x2328.115\x237,1\x23if',2:'100000008',4:10,8:true,9:true,13:'100\x25',14:'FORCEDLEFT',17:true,18:true,19:true,20:'0',25:true,41:false,44:{MaxInputLen:'10'}}" lsevents="{FieldHelpPress:[{ClientAction:'none'},{modalNo:'0',rgv:[{id:'28.115',submit:'X',type:'GuiGridView'}]}]}" type="text" maxlength="10" tabindex="-1" ti="-1" class="lsTblEdf3 lsTblEdf3NoEllipsis urBorderBox lsControl--explicitwidth lsField__input" readonly="true" value="100000008" autocomplete="off" autocorrect="off" name="grid#28.115#7,1#if" style="vertical-align:top;text-align:left;" title="">
That's the way I'm trying to find it , but being failed:
var element = wait.Until(x => x.FindElement(By.XPath("//input[contains(#id,'115#7,1')]")));
You may use ExpectedConditions. See code below.
var elem = wait.Until(ExpectedConditions.ElementExists(By.CssSelector("input[id*='115#7,1']")));

Aspx in different environments

this my first question so sorry if the format isn't perfect yet.
I've a small app communicating via an MSMQ, so I decided to make an aspx webpage to monitor the content of that msmq.
I've tested that page in our acceptance server, works perfectly fine.
However, when I test it in our prod server, if the msmq isn't empty, I have an error page saying "SERVER ERROR IN MSMQ MONITORING : Cannot find a formatter capable of reading this message".
Here's the relevant section of the code :
#{
var errorMessage = "";
string queueName = ".\\Private$\\cotfollowupqueue";
System.Messaging.MessageQueue myqueue = new System.Messaging.MessageQueue(#queueName);
System.Messaging.Message[] msgs = new System.Messaging.Message[0];
try {
msgs= myqueue.GetAllMessages();
}
catch (Exception ex)
{
errorMessage = "An error occured : " + ex.Message.ToString();
}
myqueue.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(AwaitingOrder_DTO) });
}
#section featured {
<section class="featured">
<div class="content-wrapper">
<hgroup class="title">
<h1>#Page.Title .</h1>< br/>
<h2>Content of the MSMQ</h2>
</hgroup>
<p>This table will show you the content of the MicroSoft Message Queuing used for COT Follow Up.</p>
<p>
<!-- ADD THINGS HERE -->
#errorMessage
<table border="1">
<tr>
<td>COT ID</td>
<td>Row ID</td>
<td>Number of attempts</td>
<td>Next attempt at</td>
<td>Cot Message</td>
<td>Status</td>
<td>Success</td>
</tr>
#foreach (var msg in msgs)
{
myqueue.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(AwaitingOrder_DTO) });
var message = (AwaitingOrder_DTO)msg.Body;
<tr>
<td>#message.COTID</td>
<td>#message.rowId</td>
<td>#message.numberOfRetries</td>
<td>#message.nextAttempt</td>
<td>#message.cotMessage</td>
<td>#message.status</td>
<td>#message.success</td>
</tr>
}
</table>
</p>
</div>
</section>
}
The code is a copy pasta from one server to the other, and the deployment was done exactly in the same way. Would anyone know what I can look at to correct this?
I've searched for solutions but : I have a formatter, so it doesn't seem to be the problem.
The code works on another server, so I guess it might be unrelated to the code itself but to environment.
I've checked with "go to definition" where the page got "awaiting order dto" and "queue writer" definition from, and it sends me to a "from metadata" page which makes me wonder if that might be the trouble, but I highly doubt that, since even if the queue writer isn't in the direct metadata, the page is able to send messages to the msmq, just not to read it's content.
Any idea?
(Sorry for long post)
So, I've found the origin of my problems:
--As stated, the f12/see definition option showed me metadata, but I didn't find any real class/code corresponding.
==> This led me to search information about where you put the code in asp.net web app. Answer is : in "app code folder", which is then compiled to make "app code dll". Guess what? You can't just copy paste that file and hope it'll work, apparently.
So I re-took source code, re-compiled, and replaced the "failing" files. Tadaaa, I can monitor my msmq.
(Also had a typo to correct because the page failed to create correct DTO for the transfer, and had to clean the queue multiple times since it's in prod and I can't simply send wrong informations but hey. That's how you learn).
At least now I'm registered on SO.

How to grab session ID - Xpath, C#

I'm trying to read the value of a session ID which is served up to a client page (a pin that can then be given to other users who want to join the session), which according to chrome developer tools, is located within this element:
<input type="text" size="18" autocomplete="off" id="idSession" name="idSession" class="lots of stuff here" title="" ">
So far I've been using C# and Xpath to navigate around the site successfully, for testing purposes, but I just can't get hold of the pin that is generated within id="idSession", or by using any other identifier through Xpath. There's a bunch of jquery stuff going on in the background, but neither is it showing up there (again, the code knows about the on-screen locations in the .js files for the ID, but that's it).
I'm new to all of this so would really appreciate a nudge in the right direction, ie. what different tools I need for this, what am I missing etc. what I need to read up on.
Thanks a lot.
What about //input[#id='idSession']/#value to get the content
Also, including a link to a helper library for creating xpath using linq-esq syntax
var xpath = CreateXpath.Where(e => e.TargetElementName == "input" &&
e.Attribute("id").Text == "idSession").Select(e => e.Attribute("value"));
http://unit-testing.net/CurrentArticle/How-to-Create-Xpath-From-Lambda-Expressions.html

Why doesn't this JavaScript display a confirm box?

I am trying to fix some bugs in a product I inherited, and I have this snippet of javascript that is supposed to hilight a couple of boxes and pop up a confirm box. What currently happens is I see the boxes change color and there is a 5 or so second delay, then it's as if the missing confirm just accepts itself. Does anyone smarter than I see anything amiss in this code?
function lastCheckInv() {
document.getElementById("ctl00$ContentPlaceHolderMain$INDet$txtInvNumber").style.background = "yellow";
document.getElementById("ctl00$ContentPlaceHolderMain$INDet$txtInvNumber").focus();
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_AddCharges").style.background = "yellow";
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_lblFreight").style.background = "yellow";
bRetVal = confirm("Are you sure the information associated with this invoice is correct?");
return bRetVal;
}
The only thing I can think of is if one of the lines before the confirm is throwing an exception and you're never actually getting to the confirm.
If you're using IE, make sure script debugging is enabled. If you're using Firefox, install the Firebug add-on and enable it for your website.
Or, for very primitive debugging, just put alerts after each statement and figure out where it's bombing.
You should use the following method to reference your controls from JavaScript:
document.getElementById(<%= txtInvNumber.ClientID %>).style.background = "yellow"
If that doesn't help, try setting a breakpoint in your JavaScript and stepping through it to see where it's failing.
This test script ran fine for me in IE, Firefox, and Opera. So there doesn't seem to be anything wrong with your basic syntax. The problem is either in the ID's (which doesn't fit with the fact that it acts as if confirmed after 5 seconds) or in some other conflicting JavaScript on the page. It will be difficult to help you without seeing more of the page.
<script language="javascript">
function lastCheckInv() {
document.getElementById("test1").style.background = "yellow";
document.getElementById("test1").focus();
document.getElementById("test2").style.background = "yellow";
document.getElementById("test3").style.background = "yellow";
bRetVal = confirm("Are you sure?");
return bRetVal;
}
</script>
<form method="get" onsubmit="return lastCheckInv();">
<input id="test1" name="test1" value="Hello">
<input id="test2" name="test2" value="Hi">
<input id="test3" name="test3" value="Bye">
<input type="submit" name="Save" value="Save">
</form>
A few thoughts: Could be the .focus() call is hiding your confirm behind the page? Or could it be that one of your control id's is not correct causing, the .style.background references to fail?
You should set the focus after showing the confirm box, otherwise the confirm box will grab focus away, making that line meaningless.
Don't hard-code ASP.Net id's like that. While they typically are consistent, a future version of ASP.net won't guarantee the same scheme, meaning your setting yourself up for pain when it comes time to update this code at some point in the future. Use the server-side .ClientID property for the controls to write those values into the javascript somewhere as variables that you can reference.
Update:
Based on your comment to another response, this code will result in a postback if the function returns true. In that case, there's not point in running the .focus() line at all unless you are going to return false.
I do not like accesing objects directly by
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_lblFreight").style.background = "yellow";
If the object is not returned JavaScript will error out. I prefer the method of
var obj = document.getElementById("ctl00_ContentPlaceHolderMain_INDet_lblFreight");
if(obj)
{
obj.style.background = "yellow";
}
My guess is you are trying to access an object that is not on the DOM, so it never gets to the confirm call.
It might be worth checking that the elements actually exist. Also,try delaying the focus until after the confirm():
function lastCheckInv() {
var myObjs,bRetVal;
myObjs=[
"ctl00_ContentPlaceHolderMain_INDet_AddCharges",
"ctl00_ContentPlaceHolderMain_INDet_lblFreight",
"ctl00$ContentPlaceHolderMain$INDet$txtInvNumber"
];
bRetVal = confirm("Are you sure the information associated with this invoice is correct?");
for (var i=0, j=myObjs.length, myElement; i<j; i++){
myElement=document.getElementById(myObjs[i]);
if (!myElement){
// this element is missing
continue;
}
else {
// apply colour
myElement.style.background = "yellow";
// focus the last object in the array
if (i == (j-1) ){
myObj.focus();
}
}
}
return bRetVal;
}
function lastCheckInv()
{
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_txtInvNumber").style.background = "yellow";
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_txtInvNumber").focus();
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_AddCharges").style.background = "yellow";
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_lblFreight").style.background = "yellow";
return confirm("Are you sure the information associated with this invoice is correct?");
}
The first two lines in your function are wrong, $ are in the UniqueID of an ASP.Net Control.
On Clientside you have to use the ClientID, replace $ with _ .
If you are sure that the Controls exists, the
code above might work.
Is bRetVal actually declared anywhere?
If not, "var bRetVal = confirm...." is a friendly way of telling jscript that it is a variable.

Categories