GetImageThumbnail() with dimensions - asp.net

In our ASP.NET MVC 3 We are currently generating thumbnail images on the fly with the following code:
public void GetImageThumbnail(string imageName)
{
WebImage wbImage = new WebImage("~/assets/images/gallery/"+imageName+".jpg");
int width = 220;
wbImage.Resize(width, (int)((double)wbImage.Height * width / wbImage.Width));
wbImage.FileName = imageName+"_small.jpg";
wbImage.Write();
}
and displaying them in the view like this:
<img src="#Url.Action("GetImageThumbnail", new {imageName = "motherboard"})" alt="" />
How can we control the image size on the view and generate the complete <img> tag from scratch? We need to specify the image dimension and obtain an <img> tag the contains the width and height properties.
Thanks.

My first thought is to create your own HTML helper method which does all of the work. Something you would consume like:
#Html.ThumbnailImg("motherboard")
That method does the thumbnail work and can output the full desired markup. More info: http://www.asp.net/mvc/tutorials/older-versions/views/creating-custom-html-helpers-cs. For what it's worth, I prefer the extension method design. It seems more palatable to other devs.
UPDATE:
There is a little bit of chicken-and-egg that I didn't think about before. Perhaps something like:
public static MvcHtmlString ThumbnailImg(
this HtmlHelper html,
UrlHelper url,
String imageName,
String elementID,
String altText)
{
var img = new TagBuilder("img");
if (String.IsNullOrEmpty(elementID) == false) img.MergeAttribute("id", elementID);
if (String.IsNullOrEmpty(altText) == false) img.MergeAttribute("alt", altText);
// Generate and cache thumnail here, determining height and width
// ...
var src = url.Action("GetImageThumbnail", new { imageName = imageName });
img.MergeAttribute("height", height);
img.MergeAttribute("width", width);
img.MergeAttribute("src", src);
return MvcHtmlString.Create(img.ToString(TagRenderMode.SelfClosing));
}

Related

QrCoder Asp.Net - How to remove noise?

Right now I'm creating my QR-Code using QrCoder from Asp.Net. You can see my code below:
SvgQrCode:
public void UpdateText(string value)
{
using (var qrGenerator = new QRCodeGenerator())
{
using (var qrCodeData = qrGenerator.CreateQrCode(value, QRCodeGenerator.ECCLevel.Q))
{
using (var qrCode = new QRCode(qrCodeData))
{
using (var bitmap = qrCode.GetGraphic(1, Color.Black, Color.White, false))
{
Image.FromData(bitmap);
}
Text = value;
} } } }
Xml:
<Image Source="{Binding Element.ImageSource}"
RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased"
Width="{Binding Element.Width}"
Height="{Binding Element.Height}"
Stretch="Uniform">
What happens:
The generated QR-Code has some light noise that you can see here in the screenshot on the left side(left side Gray8, right side BlackWhite):
What I tried:
I changed in the method Decode the Pixelformats from Gray8 to BlackWhite. The result is the screenshot above (qr code on the right side).
internal static BitmapSource Decode(string value, int? pixelWidth, BitmapCacheOption cacheOption = BitmapCacheOption.OnLoad)
{
// ..some code..
var grey = new FormatConvertedBitmap(bitmap, PixelFormats.Gray8, BitmapPalettes.Gray256, 1.0);
return grey;
}
Another thing that I tried is changing qrCode.GetGraphic(1) to something higher like qrCode.GetGraphic(10), which increases the pixels per module. But this is not a clean way to fix the problem, because the noise is just getting realy small(so you can hardly see it anymore) and the pixel per module are getting increased.
My Problem: I'm using the method decode for qr codes, bar codes and images. So If I would add an image it would be black and white. Of course I can use an if-statement and check what if its an image or or qr/bar-code. But why is PixelFormats.Gray8 creating noise? Why is it not clean?
I found the problem. I overlooked those lines and didnt realize that .jpeg was choosen as format:
public void FromData(Bitmap bitmap)
{
using (var ms = new MemoryStream())
{
bitmap.Save(ms, ImageFormat.Jpeg);
//...

Xamarin Forms add new controls dinamically in the content via code

I have a form in my Xamarin project that its result is something like that:
Basically there is a header (1) and a body of this form (2). The header is quite simple build with AbsoluteLayout.
For creating the body (2) I've created my component to show a tab control and then for each tab a specific grid with images and text. For each section, I'm checking in the database how many records there are for it and change the text. This activity is very long and I'm trying to understand why and how I can improve speed.
Then I should cut the corner to add later in my page the tab control so the user can see immediately the header and after few second all page. The code is like the following:
public class MyPage : WaitingPage
{
public MyPage(Card card)
{
LoadingMessage = "Loading...";
ShowLoadingFrame = true;
ShowLoadingMessage = true;
ShadeBackground = true;
WaitingOrientation = StackOrientation.Vertical;
IsWaiting = true;
StackLayout stackPage = new StackLayout() {
BackgroundColor = Color.FromHex("#fff"),
Children = {
ShowHeader(card),
}
};
Content = stackPage;
Task.Yield();
Task.Run(async () => {
Content = await ShowDetails(card);
});
IsWaiting = false;
}
}
I tried different ways to add the content from await ShowDetails(card); but nothing happens. Basically the content doesn't change unless await ShowDetails(card); is executed. I discovered Task.Yield(); (you can wait the page is rendered and showed and then continue) but in this case doesn't work. And also WaitingPage doesn't show the message.
Any suggestions or help? Thank you in advance

How to call async function inside Web form/ MVC Razor Asp.net? [duplicate]

Is it possible to await on tasks in Razor .cshtml views?
By default it complains that it can only be used in methods marked with async so I'm wondering if maybe there is a hidden switch somewhere that enables it?
In ASP.NET Core 2.1, you can use await in Razor views.
See https://learn.microsoft.com/en-us/aspnet/core/mvc/views/partial?view=aspnetcore-2.1
Example:
#await Html.PartialAsync("../Account/_LoginPartial.cshtml")
I've wanted something like this for a long time - a lot of the pages we write could be thrown together by a Jr Dev if they didn't have to write a bunch of queries; and, it's the same basic query boilerplate every time anyway - why should they have to write them for each Controller, when the majority of their work is to get content up? I use C# so I don't have to deal with memory management, why should an HTML coder have to deal with query details?
There is a trick you can use to sort of implicitly load data async into the View. First, you define a class that expresses what data you want. Then, at the top of each View, instantiate that class. Back in the Controller, you can lookup the View you know you're going to use, open it, then compile that class. You can then use it to go get the data the View will need, async, in the Controller the way MVC enforces. Finally, pass it off with a ViewModel to the View as MVC prescribes, and, through some trickery - you have a View that declares what data it's going to use.
Here's a StoryController. Jr Devs write stories as simple .cshtml files without having to know what a Controller, database or LINQ is:
public class StoryController : BaseController
{
[OutputCache(Duration=CacheDuration.Days1)]
// /story/(id)
public async Task<ActionResult> Id(string id = null)
{
string storyFilename = id;
// Get the View - story file
if (storyFilename == null || storyFilename.Contains('.'))
return Redirect("/"); // Disallow ../ for example
string path = App.O.AppRoot + App.HomeViews + #"story\" + storyFilename + ".cshtml";
if (!System.IO.File.Exists(path))
return Redirect("/");
return View(storyFilename);
All this does for now is go get the View file based on the URL, allowing something like WebForms (except inside MVC and using Razor). But we want to show some data - in our case, people and projects that accumulate in the database - with some standard ViewModels and Partials. Let's define how and compile that out. (Note that ConservX happens to be the core Project namespace in my case.)
public async Task<ActionResult> Id(string id = null)
{
string storyFilename = id;
// 1) Get the View - story file
if (storyFilename == null || storyFilename.Contains('.'))
return Redirect("/"); // Disallow ../ for example
string path = App.O.AppRoot + App.HomeViews + #"story\" + storyFilename + ".cshtml";
if (!System.IO.File.Exists(path))
return Redirect("/");
// 2) It exists - begin parsing it for StoryDataIds
var lines = await FileHelper.ReadLinesUntilAsync(path, line => line.Contains("#section"));
// 3) Is there a line that says "new StoryDataIds"?
int i = 0;
int l = lines.Count;
for (; i < l && !lines[i].Contains("var dataIds = new StoryDataIds"); i++)
{}
if (i == l) // No StoryDataIds defined, just pass an empty StoryViewModel
return View(storyFilename, new StoryViewModel());
// https://stackoverflow.com/questions/1361965/compile-simple-string
// https://msdn.microsoft.com/en-us/library/system.codedom.codecompileunit.aspx
// https://msdn.microsoft.com/en-us/library/system.codedom.compiler.codedomprovider(v=vs.110).aspx
string className = "__StoryData_" + storyFilename;
string code = String.Join(" ",
(new[] {
"using ConservX.Areas.Home.ViewModels.Storying;",
"public class " + className + " { public static StoryDataIds Get() {"
}).Concat(
lines.Skip(i).TakeWhile(line => !line.Contains("};"))
).Concat(
new[] { "}; return dataIds; } }" }
));
var refs = AppDomain.CurrentDomain.GetAssemblies();
var refFiles = refs.Where(a => !a.IsDynamic).Select(a => a.Location).ToArray();
var cSharp = (new Microsoft.CSharp.CSharpCodeProvider()).CreateCompiler();
var compileParams = new System.CodeDom.Compiler.CompilerParameters(refFiles);
compileParams.GenerateInMemory = true;
compileParams.GenerateExecutable = false;
var compilerResult = cSharp.CompileAssemblyFromSource(compileParams, code);
var asm = compilerResult.CompiledAssembly;
var tempType = asm.GetType(className);
var ids = (StoryDataIds)tempType.GetMethod("Get").Invoke(null, null);
using (var db... // Fetch the relevant data here
var vm = new StoryViewModel();
return View(storyFilename, vm);
}
That's the majority of the work. Now Jr Devs can just declare the data they need like so:
#using ConservX.Areas.Home.ViewModels.Storying
#model StoryViewModel
#{
var dataIds = new StoryDataIds
{
ProjectIds = new[] { 4 }
};
string title = "Story Title";
ViewBag.Title = title;
Layout = "~/Areas/Home/Views/Shared/_Main.cshtml";
}
#section css {
...
I landed on this question because I am a newbie to Razor and I wanted to display a simple "loading..." screen while my Controller Code was calculating data.
So I found this link: https://www.codeproject.com/Articles/424745/MVC-Razor-In-Progress-Icon which was helpful, but because I was a total novice at Razor, I was unable to make this work.
What finally worked for me was the following.
1) Add the "loading" div as suggested in the code project to my .cshtml file:
<div id="divLoading" style="margin: 0px; padding: 0px; position: fixed; right: 0px;
top: 0px; width: 100%; height: 100%; background-color: #666666; z-index: 30001;
opacity: .8; filter: alpha(opacity=70);display:none">
<p style="position: absolute; top: 30%; left: 45%; color: White;">
Loading, please wait...<img src="../../Content/Images/ajax-loading.gif">
</p>
</div>
2) Modify my Razor form from
<input type="submit" value="Go"/>
to
<input type="button" value="Go" onclick="JavascriptFunction()" />
3) Create the JavascriptFunction() in my .cshtml page:
<script type="text/javascript" language="javascript">
function JavascriptFunction() {
$("#divLoading").show();
$('form').submit();
}
</script>
If I understand all of the above correctly, what this does is execute the function JavascriptFunction when I press the Go button.
The JavascriptFunction does 2 things:
1) Change the view of the page by showing the previously hidden (display:none) divLoading div.
2) Submit all the forms on this page (I only have one, so it submits the form the same as if I had they type submit on the button)
After the Controller launched by the form submit is done, it loads a new view on a new page, and the initial page (and the "loading" div) is gone. Mission accomplished.
You can await calls in razor pages? I have a Blazor app and most of my methods are async:
Razor page:
<MatFAB Icon="#MatIconNames.Autorenew" Style="transform:scale(0.8); background:#333;"
OnClick="#(async () => await OnInitializedAsync())"></MatFAB>
This is a MatBlazor FloatingActionButton which calls the life time cycle event OnInitializedAsync()
C# Code:
protected override async Task OnInitializedAsync()
{
// Do something like get data when the form loads
}
No, that's not possible and you shouldn't need to do it anyway. Razor views should contain markup and at most some helper call. async/await belongs to your backend logic.
If you really need it, you can do this, it will be ugly, but it will work.
In View
#{
var foo = ViewBag.foo;
var bar = ViewBag.bar;
}
In Controller
public async Task<ActionResult> Index()
{
ViewBag.foo = await _some.getFoo();
ViewBag.bar = await _some.getBar();
return View("Index");
}
Following on MaxP's answer, it's easy to return a value from that code, despite Knagis comment:
#{
int x = DoAsyncStuffWrapper().Result;
}
#functions {
async Task<int>DoAsyncStuffWrapper()
{
await DoAsyncStuff();
}
}
I know this is an older thread, but I'll add my input just in case someone else finds it useful. I ran into this problem working with the new MongoDB driver in ASP.Net MVC - the new driver (for now), only implements async methods and returns async cursors, which can't be used in a foreach because asynccursor doesn't implement IEnumerable. The sample code typically looks like:
while(await cursor.movenextasync)
var batch=cursor.current
foreach(var item in batch)
--do stuff here--
But, this doesn't work in razor, because views are inherently not async, and await doesn't cut it.
I got it to work by changing the first line to:
while(cursor.MoveNextAsync().Result)
which returns true until the cursor hits the last entry.
Hope that helps!

How to render html code with asp.net class

I need to be able to add a dynamic html code to a random cshtml page using my class:
public class HTMLRenderClass
{
//--here I generate html code
public void RenderControll()
{
LiteralControl ControlGroup = new LiteralControl();
ControlGroup.Text = "<h1>Here will be html code generated above</h1>";
Page p = HttpContext.Current.Handler as Page;
if (p != null) p.Controls.Add(ControlGroup);
else { throw new UserFriendlyException("Page still null"); }
}
}
so that inside cshtml I could call it like
#{
HTMLRenderClass c = new HTMLRenderClass();
c.RenderControll();
}
But the problem is that I don't know how to add my html to the page I need, because "HttpContext.Current.Handler as Page" is always null. Are there any solutions of that situation in which I still could use c.RenderControll() method without passing any "Page object" parameters?
If not, then what exactly should I pass to my class to place my dynamic html block inside static one?

How to properly sanitize content with AntiXss Library?

I have a simple forums application, when someone posts any content, i do:
post.Content = Sanitizer.GetSafeHtml(post.Content);
Now, i am not sure if i am doing something wrong, or what is going on, but it does not allow almost no html. Even simple <b></b> is too much for it. So i guess that tool is totally useless.
Now my question: Can anyone tell me how should i sanitize my users inputs so that they can post some images(<img> tags) and use bold emphasis etc?
It seems that many people find the sanitizer rather useless. Instead of using the sanitizer, just encode everything, and decode safe parts back:
private static readonly IEnumerable<string> WhitelistedTags =
new[] { "<b>", "</b>", "<i>", "</i>" };
private static readonly (string Encoded, string Decoded)[] DecodingPairs =
WhitelistedTags
.Select(tag => (Microsoft.Security.Application.Encoder.HtmlEncode(tag), tag))
.ToArray();
public static string Sanitize(string html)
{
// Encode the whole thing
var safeHtml = Microsoft.Security.Application.Encoder.HtmlEncode(html);
var builder = new StringBuilder(safeHtml);
// Decode the safe parts
foreach (var (encodedTag, decodedTag) in DecodingPairs)
{
builder.Replace(encodedTag, decodedTag);
}
return builder.ToString();
}
Please note that it's nearly impossible to safely decode an IMG tag, since there are really simple ways for an attacker to abuse this tag. Examples:
<IMG SRC="javascript:alert('XSS');">
<IMG SRC=javascript:alert('XSS')>
Take a look here for more a thorough XSS Cheat Sheet
This post best describes the issues with the Anti XSS library and provides a good work around that whitelists a set of tags and attributes.
I'm using this solution in my project and it seems to work great.
There is a quite simple way to block the threat by just getting rid of the "dangerous" tags.
string SanitizeHtml(string html)
{
html = System.Web.HttpUtility.HtmlDecode(html);
List<string> blackListedTags = new List<string>()
{
"body", "script", "iframe", "form", "object", "embed", "link", "head", "meta"
};
foreach (string tag in blackListedTags) {
html = Regex.Replace(html, "<" + tag, "<p", RegexOptions.IgnoreCase);
html = Regex.Replace(html, "</" + tag, "</p", RegexOptions.IgnoreCase);
}
return html;
}
With this the user will still see what is within the dangerous script, but it won't harm anything.

Resources