I used Url data Annotation in MVC as follow:
[Url]
[DisplayName("ULink")]
public string ULink { get; set; }
But some times it does not even allow the code with proper url ; it fails in ModelState.IsValid in the server side giving the following error message.
The Link to ULink field is not a valid fully-qualified http, https, or ftp URL.
Please Suggest
The error message indicates that the URL must be fully-qualified.
I.E. It's missing the HTTP/HTTPS/FTP protocol.
EX: https://www.google.com, not www.google.com.
Related
Working with Kentico 11.0.26 CMS and a MVC website.
Have a custom content-only page type with an image field. After the image is uploaded on a page I need to display it on MVC site. But Kentico's generated code MyPageTypeProvider.GetMyPageType((int nodeId, string cultureName, string siteName) returns a page object that only contains the GUID of the image. No bytes, no URL.
How do I get the bytes or the URL of the uploaded image?
If you need the bytes, you can do this:
var attachment =DocumentHelper.GetAttachment(guid, SiteContext.CurrentSiteName, true);
var bytes = attachment.AttachmentBinary;
If you want a URL to the image, you can do something like this:
imageUrl = $"/getattachment/{guid}/attachment.aspx"
This documentation explains more ways to work with attachments.
You will need to either resolve the URL, or get file by GUID. Problem is, that Kentico Nuget API does not seem to provide enough options to get file binaries.
HelperMethods from Kentico.Content.Web.MVC NuGet seem to be good start:
https://github.com/Kentico/Mvc/tree/master/src/Kentico.Content.Web.Mvc
With these you can get file URL and use:
using (var client = new WebClient())
{
client.DownloadFile("http://example.com/file/song/a.mpeg", "a.mpeg");
}
Or you can write your own class or service, reference Kentico DLLs and use:
AttachmentBinaryHelper.GetFilePhysicalPath(string siteName, string guid, string extension)
I'm using the Kendo AutoComplete client javascript widget, which sends server requests such as the following:
https://domainName/Proto2/api/Goal/Lookup?text=ABC&goalId=8b625c56-7b04-4281-936f-b88d7ca27d76&filter%5Blogic%5D=and&filter%5Bfilters%5D%5B0%5D%5Bvalue%5D=&filter%5Bfilters%5D%5B0%5D%5Boperator%5D=contains&filter%5Bfilters%5D%5B0%5D%5Bfield%5D=Description&filter%5Bfilters%5D%5B0%5D%5BignoreCase%5D=true&_=1423833493290
The MVC server side method to receive this is:
[Route("api/Goal/Lookup")]
[HttpGet] // if the action name doesn't start with "Get", then we need to specify this attribute
public ICollection<IAllegroGoalContract> Lookup(Guid goalId, string text = "")
The problem occurs if the client sends an empty value for the text parameter (ex: text=&goalId=8b625c56-7b04-4281-936f-b88d7ca27d76). In this case .net returns the following error.
"System error - unable to process parameters
(goalId,text,text.String) - invalid data detected"
I've tried various Route attribute values:
[Route("api/Goal/Lookup/{goalId:guid},{text?}")]
[Route("api/Goal/Lookup/{text?}")]
Looks like your parameters are used as a filter, so instead of the GoalId and Text parameters to be part of the route, define a class like this:
public class LookupOptions
{
public Guid GoalId { get; set; } // change this to Guid? if the client can send a nullable goalId.
public string Text { get; set; }
}
So your method signature will be :
[Route("api/Goal/Lookup")]
[HttpGet]
public ICollection<IAllegroGoalContract> Lookup([FromUri]LookupOptions options)
{
// Note that [FromUri] will allow the mapping of the querystring into LookupOptions class.
}
Now, you can pass your options from the client as part of the Query string and it will be assigned to the LookupOptions parameter.
Hope this helps.
I have a view (with one or more images) that I also want to use as the body of an email message. The Model serving the view uses Url.Content() to retrieve the absolute image path. This approach works fine for web pages, but when I render the exact same view as the body of the email, then the image can not be found which is suggested by the incomplete path from the rendered html.
<img src="/Media/fe882a1d-3b77-4264-ab91-cade985ecbed.JPG"/>
I know that this problem can be fixed if I could access the full url such as with Url.Action with the
Request.Url.Scheme
overload for protocol. Is there a way to determine the fully qualified URL from Url.Content?
Try writting your own url extension method and resolve with the help of Uri.GetLeftPart & UriPartial.Authority
public static class UrlExtensions
{
public static string AbsoluteContent(this UrlHelper urlHelper
, string contentPath)
{
Uri requestUrl = urlHelper.RequestContext.HttpContext.Request.Url;
string absolutePath = string.Format("{0}{1}",
requestUrl.GetLeftPart(UriPartial.Authority),
urlHelper.Content(contentPath));
return absolutePath;
}
}
Then use Url.AbsoluteContent("~/media/image.jpeg") in your pages. It will render http://domain/media/image.jpeg
Trying to use the StartSignInWithTwitter method. When the method is called soon after an exception is thrown. This is using the latest version of DotNetOpenAuth. Would it have anything to do with me developing and running with locally? (VS2010) Is this how I should be doing authentication in the first place? I do see some different ways in the Samples pack that is included with the source.
{"The remote server returned an error: (401) Unauthorized."}
My code looks like below:
public void TwitAuthInit()
{
TwitterConsumer.StartSignInWithTwitter(false).Send();
}
public ActionResult TwitAuth()
{
if (TwitterConsumer.IsTwitterConsumerConfigured)
{
string screenName;
int userId;
if (TwitterConsumer.TryFinishSignInWithTwitter(out screenName, out userId))
{
FormsAuthentication.SetAuthCookie(screenName, false);
return RedirectToAction("Home", "Index");
}
}
return View();
}
To answer your question about "Is this how I should be doing authentication in the first place?":
You probably shouldn't be calling SetAuthCookie(screenName, false) with your screenName, since screen names (I believe) can be recycled. You should instead log the user in using a unique ID, either one you create in your own user database or Twitter's, and then use the screen name only as an alias that is displayed to the user (and perhaps other users if this user were to post something for public viewing). Otherwise, when Twitter recycles a username, that user will inherit all the data from the old user on your site -- not good.
Wanted to confirm that the 401 error is indeed solved by setting a non-empty callback URL on the twitter app config page.
From the Application Type block of the settings page:
To restrict your application from using callbacks, leave this field
blank.
You have to go into TwitterConsumer.cs and change the following URLs:
Request token URL https://api.twitter.com/oauth/request_token
Authorize URL https://api.twitter.com/oauth/authorize
Access token URL https://api.twitter.com/oauth/access_token
As Twitter changed their URLs. I didn't get the memo and spent way too much time debugging this.
For a POST method, the W3 specs say:
If a resource has been created on the origin server, the response
SHOULD be 201 (Created) and contain an entity which describes the
status of the request and refers to the new resource, and a Location
header (see Section 10.4).
http://www.ietf.org/internet-drafts/draft-ietf-httpbis-p2-semantics-05.txt (section 8.5)
The standard response actually seems to be to send a Redirect to the newly created resource.
I'm building my site with ASP.NET MVC, and tried to follow the spec, so created a ResourceCreatedResult class:
public class ResourceCreatedResult : ActionResult
{
public string Location { get; set; }
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Clear();
context.HttpContext.Response.StatusCode = 201;
context.HttpContext.Response.ClearHeaders();
context.HttpContext.Response.AddHeader("Location", Location);
}
}
And my action looks something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateNew(string entityStuff)
{
Entity newEntity = new Entity(entityStuff);
IEntityRepository entityRepository = ObjectFactory.GetInstance<IEntityRepository>();
entityRepository.Add(newEntity);
ActionResult result = new ResourceCreatedResult()
{ Location = Url.Action("Show", new { id = newEntity.Id }) };
return result;
}
However, IE, Firefox and Chrome all fail to redirect to the new resource. Have I messed up generating the correct response, or do web browsers not expect this type of response, instead relying on servers to send a Redirect response?
To be explicit, browsers (including modern browsers like Firefox 3 and IE8) do not "take the hint" and follow up an HTTP 201: Created response with a GET request to the URI supplied in the Location header.
If you want browsers to go to the URI supplied in the Location header, you should send an HTTP 303: See Other status instead.
Redirect after post or post/redirect/get is something your application must do to be user friendly.
Edit. This is above and beyond the HTTP specifications. If we simply return a 201 after a POST, the browser back button behaves badly.
Note that Web Services requests (which do NOT respond to a browser) follow the standard completely and do NOT redirect after post.
It works like this.
The browser POSTS the data.
Your application validates the data. If it's invalid, you respond with the form so they can fix it and POST.
Your application responds with a redirect.
The browser gets the redirect and does a GET.
Your application sees the GET and responds.
Now -- hey presto! -- the back button works.
My solution is to respond with a '201 Created' containing a simple page with a link to the new resource, and a javascript redirect using location.replace().
This lets the same code work for API and browser requests, plays nicely with Back and Refresh buttons, and degrades gracefully in old browsers.
As stated in the spec the response SHOULD be a HTTP 201 with redirect. So it isn't mandatory for a browser vendor to implement the correct answer...
You should try to change to a 30x code to see if it is correctly redirected. If so, it's a browser problem, else it may come from your code (I don't know anything in ASP.NET so I can't "validate" your code)
Shouldn't that only count for when something is "Created" and therefore a simple redirect to action should be genuinely sufficient?