2024-10-13

ASP.NET Route results in 404 when the route ends with a filename

The Problem 

I had a custom route set on an API method that was to be used to delete a file from a ZIP created for an expense.

[HttpDelete]
[Route("api/reimbursements/expense/{expenseId}/receipt/{receiptFileName}")]
public async Task<IHttpActionResult> RemoveReceiptFromExpense(string expenseId, string receiptFileName) 
{
    // code to perform the remove here...
}

Everytime I tried to hit this endpoing using JavaScript's "fetch" API using the DELETE verb, it would always result in a 404. I spent more than an hour banging my head against the wall trying various different route changes, but could not understand why other endpoints on the same API controller worked except for this one.

The Reason

It finally dawned on me that ASP.NET has handlers that are filename-based, and they were intercepting my request and not finding a match that could fill it.  It wouldn't pass it to the routing handler that would go find my template and handle it.

The Solution

I don't have time today to research the more elegant solution, which would be to get the routing system to ignore the filename checks for this route and handle it with the filename at the end of the route, so I chose to reverse the template and put the receipt filename first and the expenseId last.  Now it looks like this:

[HttpDelete]
[Route("api/reimbursements/receipt/{receiptFileName}/expense/{expenseId}")]
public async Task<IHttpActionResult> RemoveReceiptFromExpense(string expenseId, string receiptFileName) 
{
    // code to perform remove here...
}

This made it work with no issues.  This is a quick solution for others experiencing the same issue.  

If you want to keep your route with the filename at the end, you will need to research how to force the "Extensionless" handlers to intercept your request for that template.  As I mentioned before, I don't have time today to research that, but needed to document this with the little time I have, so I can remember why next time I run into this issue.


2020-02-19

Access ASP.NET website hosted in IIS Express from another machine on the local network (VS 2019)

I needed to test Mac Safari against a website I was developing on a Windows machine. Instead of being required to publish for every change, I wanted to just expose IIS Express across the LAN and hit the website that way. In order to do so, I had to do the following:

  1. Run Visual Studio 2019 as Administrator
  2. Edit {ProjectRoot}/.vs/{WebProjectName}/config/applicationhost.config
  3. In the <sites> section, add a binding under the website project's <site> definition (see below):
  4. Allow the desired port through your firewall
<site name="FocusAndExecute" id="1">
  <application path="/" applicationPool="Clr4IntegratedAppPool">
    <virtualDirectory path="/" physicalPath="{path_to_site}" />
  </application>
  <bindings>
    <binding protocol="http" bindingInformation="*:51427:localhost" />
    <binding protocol="http" bindingInformation="*:51428:192.168.1.123" />
  </bindings>
</site>


After doing this and launching IIS Express from Visual Studio, I was able to hit the site from the Mac by going to:
http://192.168.1.123:51428

NOTE: You may be able to put *:51428:* instead of specifying the IP, so you can hit it by host name, etc. but I didn't play with that yet.  Feel free to leave a comment if you have a better way!

2019-11-04

[SOLVED] Visual Studio 2019 keeps rebuilding my ASP.NET Core project when I refresh my browser

A couple of weeks ago, I started noticing that Visual Studio would rebuild my code whenever I would force a refresh in my browser, even if I had just rebuilt the solution in Visual Studio before executing said refresh.  Sometimes, Visual Studio would rebuild more than once during this process, and eventually would end up with a "Cannot copy the **** files because it is being used by another process" (which I imagine was the dotnet process handling the request.

I assume the multiple builds were because I was reloading a page that also turned around and made AJAX calls back to the same site.

It got beyond super annoying, and I searched the internet and dug through settings and could not find a workaround, until today.

Under "Tools" | "Options" | "Projects and Solutions" | "ASP.NET Core" you will find an option under the "General" category called "Auto restart Kestrel server after build".  It was set to "True" in my case, and I set it to "False" and it stopped the constant rebuilding for me.

Visual Studio 2019
Tools | Options | Projects and Solutions | ASP.NET Core
Notice the description of that option states:
"Automatically build modified ASP.NET Core projects hosted in IIS Express when a browser request is received."

Unfortunately this was happening to me even after I explicitly did a full rebuild in Visual Studio, then switched to my browser to refresh the page.  So I have no idea why VS thought it was "modified" but it wasn't.  I don't have time to track down the cause of this right now, so I consider this really more of a workaround than a solution, but I hope it will help someone else avoid this madness.

I would also like to know when this option was introduced... has it been there this whole time and always defaulted to "True" and I just happened to not be bit by it until a couple of weeks ago?  Perhaps the detection mechanism for determining an ASP.NET Core project was "modified" has been broken in a recent Visual Studio release?  (I'm currently on 16.3.7, but it was happening to me on at 16.3.6 as well.)

I'd love to hear from you if you have encountered the same thing and found a better explanation and/or solution.

2018-12-30

[SOLVED] Using Bootstrap-Select and Vue together

I ran into some trouble when trying to use Vue bindings and Bootstrap-Select together that kept the visual controls from updating when options were changed via a Vue model update. 

I wrote up an article on my JavaScriptJedi.com website with both broken and working examples and an explanation about what happens.

The quick answers for making sure bootstrap-select works with Vue:

  • Prevent bootstrap-select from automatically hooking itself up to your controls by avoiding using the "selectpicker" class on the <select> element.  Use a different class like "select-picker" instead that you can manually hook up the selectpicker after your Vue model is finished mounting.
    • (Use Vue's $nextTick function inside your "mounted" handler function to ensure all components/child-components are mounted as well before setting up bootstrap-select)
  • Only use the "title" HTML attribute on your <select> when you don't have a default selected value on your <select>
  • ALWAYS call bootstrap-select's "refresh" after changing the <select>'s options via an update to the Vue model.
Please see my write-up on JavaScript Jedi and leave feedback here if you can help me enhance the article or find it helpful.  I hope this saves someone some time and frustration! 

2018-10-18

[Azure DevOps] Pending Changes gives "you are not authorized to access ..." error during Check-In

For some reason lately I have been periodically getting "... you are not authorized to access [filename.extension] ..." after clicking on the Check-In button in the "Pending Changes" section of the "Team Explorer" tab in Visual Studio.

I can't explain why this happens, but the workaround I've discovered is to click the "Refresh" button at the top of the dialog.  Once the refresh is complete, the check-in process seems to work fine.  I hope it works for you as well.


If you have run into the same and can explain why, please share in the comments.

Happy coding!

2018-06-27

ASP.NET MVC: Controlling order when using Scripts.Render

The Problem

I like concise, so when I realized I could change the following:

@Scripts.Render("~/bundles/bundle1")
@Scripts.Render("~/bundles/bundle2")
@Scripts.Render("~/bundles/bundle3")
@Scripts.Render("~/bundles/bundle4")


... to ...

@Scripts.Render("~/bundles/bundle1", "~/bundles/bundle2", "~/bundles/bundle3", "~/bundles/bundle4")

... naturally I got excited.  And it worked really well, that is, until I needed bundle3 to come before bundle1.

For a more realistic example, I have my own bundle that is dependent on KnockoutJS and requires Knockout to be loaded before my bundle is.  It would look like this:

@Scripts.Render("~/bundles/something", "~/bundles/knockout", "~/bundles/adminView")

I assumed that the bundles would be rendered in the same order I specified in that call, but it doesn't seem to play nice that way. My "~/bundles/adminView" was rendered before Knockout which broke my script.

To fix it, I removed my bundle from the rest of the list and moved it out into a separate Scripts.Render call. Now it looks like:

@Scripts.Render("~/bundles/something", "~/bundles/knockout")
@Scripts.Render("~/bundles/adminView")


Doing this forced my "adminView" bundle to be rendered after the other two because it was a separate call.

Moral of the Story

You can only "bundle" multiple bundle paths in one Scripts.Render call when none of them depend on each other, because you can't count on what order they will be rendered in. I don't know how Microsoft decides the order to render them in, but it's not necessarily the order you provide.

If order matters, use separate calls and order them the way you need to.

2018-06-13

NUnit 3.x: Asserting Equal Decimal Values with a Precision Threshold

With the newer style of doing assertions in NUnit 3.x, I was trying to figure out how to assert a decimal whose value was 1 digit precision on the right-side of the decimal, but only allowing a variance of 0.0001.

I believe this is the best practice, but will be happy to be corrected if someone knows a better way.

Assert.That(actualObject.SomeDecimalValue, Is.EqualTo(42.6m).Within(0.0001m));

2015-08-21

[SOLVED] Visual Studio "Attach to Process": Available Processes list appears empty

The Quick Answer:


  • Open the "Attach to Process" dialog (For VS2012: Alt-D | P)
  • Open Task Manager (right-click taskbar | Start Task Manager)
  • Find msvsmon.exe, highlight it, then click End Process button
  • Go back to "Attach to Process" and click "Refresh" button

The Story Behind the Answer:

I don't know if this will apply to more than Visual Studio 2012, but if it does, fantastic; please let us know in the comments.

A few days ago, my Visual Studio 2012 went wonky and decided to not show me the Available Processes in the "Attach to Process" dialog in most cases.

Here is what it should look like:

Here is what it looks like when the problem occurs.  Notice how, if I hover inside it, it will show me the tooltip for the process I'm currently over.  This suggests the list is actually populated, and double-clicking on that spot will actually make the debugger try to attach to it.  The information is there; the questions are, "Is it white font on white background?" or "Is there some other kind of painting/rendering issue with the dialog box?"

Looking around the internet, I could not seem to find the right phrase to search to find help with this issue; until I finally stumbled upon this StackOverflow question that was as close as I could get.  One answer suggested renaming MSVSMON.EXE in the x64 folder and copying the x86 version to it.

Not feeling comfortable with that, I decided to experiment with a similar concept.  I opened Task Manager and saw that msvsmon.exe was a running process.  

I executed an "End Task" on the process, and was met with this error:
Going back to my already open "Attach to Process" dialog, I clicked "Refresh" and BAM! ... there appeared the visible list.

I have done this several times, each time resulting in success.  I hope it works for you!

2015-07-03

Data Dynamics Reports - Enabling sorting on column headers causes abnormal height growth when CanGrow is True

I ran into a weird one today when working with a Data Dynamics Report (DDR) that needed sorting enabled on the column headers of a table.  Each of the TextBox controls in the column header cells were set to CanGrow=True, which was good to make sure each could fit their content.  Width was forced, so the only way for it to grow was in height.  It worked great until I enabled sorting.

Each column cell required sorting, so I added the SortExpression to each accordingly.  The instant I brought up the report in the WebReportViewer, it looked like the heights of the header cells were twice as tall as needed to fill the largest content of any of the given cells.

I then reverted my changes and the height went back to normal, making the height of the table row equal to the cell with the most content in it.  I deduced that DDR was computing height based on the extra sorting control being added to each cell, but somehow was calculating too much.  As I changed strings, the height would grow relative to the amount of content in the cell... so if the string was longer, the cell would grow all the more tall; looking double what the content in the cell was taking in height.

As I was about to give up and disable sorting on the report because the headers were taking up 1/3 of the page, I decided to try an experiment.

I turned CanGrow=False on every one of the column headers' TextBox controls (leaving the sorting enabled.)  The height went down to minimal, where only one line of text would show, and the rest was hidden because the row wasn't tall enough.  Great.  I have a baseline now!

The next step was to try changing CanGrow=True only on the cell I knew would have the most content in it.
Win!

So if you run into a similar issue, try the following:

  • Change CanGrow=False on all TextBox controls in your column headers, except the cell you know will have the largest content.

2014-07-25

[SOLVED] GrapeCity/ComponentOne ActiveReports 8 - Excel Export using WebViewer is broken

The ActiveReports engine is a great engine for rendering reports for an application.  Sometimes, though, errors will occur that have multiple reasons for why they show up; some known, others not.

It's very hard to troubleshoot those or to find solutions for them, even if you have incredible internet search skills.  That said, this solution may not work for you, but hopefully will give you a quick test to see if you can move on to another suggestion.

I was puzzled while trying to solve a problem we had in our web application where exporting via ActiveReports 8 WebViewer to PDF or DOC worked fine, but XLS for some reason returned a 404 error.

The problem turned out to be with mine that we missed laying down a DLL required by the Excel exporter (GrapeCity.ActiveReports.Export.Excel.v8.dll) called DocumentFormat.OpenXml.dll, which didn't seem to be referenced by the other Export DLLs.  

As soon as I put this in place, it started working again.

This file could be easily missed as it is not named like the other export related DLLs:
GrapeCity.ActiveReports.Export.*.v8.dll

Make sure to include that and you'll have one less reason to see a 404 error when you try exporting to Excel from ActiveReports!

On a side note, the following are all of the referenced DLLs (Microsoft DLLs excluded) for GrapeCity.ActiveReports.Export.Excel.dll in case you need to check for others also missing:
  • DocumentFormat.OpenXml.dll
  • GrapeCity.ActiveReports.Diagnostics.v8.dll
  • GrapeCity.ActiveReports.Document.v8.dll
  • GrapeCity.ActiveReports.Export.Rdf.v8.dll
  • GrapeCity.ActiveReports.Extensibility.v8.dll
  • GrapeCity.ActiveReports.v8.dll
Best of luck!