I want to localize Web Service in ASP.NET application.
I can write the following code to detect preferred client culture:
CultureInfo culture = null;
if (Request.UserLanguages!=null && Request.UserLanguages.Length>0) {
string lang = Request.UserLanguages[0];
if (!String.IsNullOrEmpty(lang)) {
try {
culture = new CultureInfo(lang) ;
}
catch {}
}
}
And use this expression to get string from resources:
WebResources.ResourceManager.GetString(stringName, culture);
But I want to use something similar to Page directive attributes:
Culture="Auto" UICulture="Auto"
Is it possible?
Firstly, this all depends on the client transmitting the headers from which the UserLanguages collection gleans it's information. Most consumers of your service if they're not browsers will not transmit that information.
Secondly, no I don't believe it is possible to do it automatically, however you could write something into the HttpContext.Items collection for the values and then wrap up
public string GetResource(string Key)
{
culture = HttpContext.Items["UserLanguage"];
WebResources.ResourceManager.GetString(stringName, culture);
}
Then your code would just read: -
GetResource("Blah");
Thanks,
Phil.
Related
I'm writing a mixed app using some MVC and some Webforms screens. I need to invoke a WebForms screen with a ReturnUrl in a hidden field. I'd like to validate the ReturnUrl before transferring back to it. MVC has an Url.IsLocalUrl function, but it doesn't seem to work on WebForm screens, so I use the UrlHelper class. But when I use it I get a NullReferenceException:
UrlHelper url = new UrlHelper();
if (url(validaddr)) <--- get NullReferenceException
{
}
Any ideas?
I use the below extension method to validate local url's in web forms. Hope this helps you too.
public static bool IsLocalURL(this string _url)
{
bool flag = false;
try
{
var url = new Uri(_url);
var ctx = HttpContext.Current;
if (url.Host.Equals(ctx.Request.Url.Host) && url.Port.Equals(ctx.Request.Url.Port))
flag = true;
}
catch { }
return flag;
}
This extension method is for string. You may create a similar for Uri class as well.
I came here trying to solve the same problem. I used RequestExtensions.IsUrlLocalToHost in System.Web.WebPages (available in nuget package Microsoft.AspNet.WebPages v3.2.6)
Doc here: https://learn.microsoft.com/en-us/dotnet/api/system.web.webpages.requestextensions.isurllocaltohost?view=aspnet-webpages-3.2
Assuming you have an HttpRequest to work with (you will probably need this anyway to compare the URL to the underlying host URL), you need to first convert your HttpRequest to HttpRequestBase:
var httpRequestBase = new HttpRequestWrapper(HttpContext.Current.Request) as HttpRequestBase;
Then you can perform:
httpRequestBase.IsUrlLocalToHost(myUrlString)
Code should be:
UrlHelper url = new UrlHelper();
if (url.IsLocalUrl(validaddr)) <--- get NullReferenceException
{
}
Is there any method for storing global variables without using cookies or session[""] in asp.net mvc ?
I know that cookies and session[""] have some disadvantages and I want to use the best method if exit.
If they are indeed global variables, you should implement the singleton pattern and have an Instance globally accessible that holds your variables.
Here is a simple example:
public sealed class Settings
{
private static Settings instance = null;
static readonly object padlock = new object();
// initialize your variables here. You can read from database for example
Settings()
{
this.prop1 = "prop1";
this.prop2 = "prop2";
}
public static Settings Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new Settings();
}
return instance;
}
}
}
// declare your global variables here
public string prop1 { get; set; }
public string prop2 { get; set; }
}
The you can use them in your code like this:
var globalvar1 = Settings.Instance.prop1;
This class with its variables will be initialized only once (when the application starts) and it will be available in your application globally.
Basically you have following options:
Cookies - valid as long as you set, must be allowed by client's browser, can be deleted by user, stored on user's PC.
Session - valid for all requests, not for a single redirect, stored on server.
ViewData - after redirect it's cleared (lives only during single request).
TempData - it's useful for passing short messages to view, after reading a value it's deleted.
ViewBag - is available only during the current request, if redirection occurs then it’s value becomes null, is dynamic so you don't have intellisense and errors may occur only in runtime.
Here - http://www.dotnet-tricks.com/Tutorial/mvc/9KHW190712-ViewData-vs-ViewBag-vs-TempData-vs-Session.html - you can find fantastic article which describes them.
Sure: HttpContextBase.Application (no expiration) or HttpContextBase.Cache (with expiration). You can access the HttpContextBase instance through the HttpContext property of the Controller class.
So... HACK ALERT... There is no good way to do an MVC 5 or 6 web app using session variables that I have found (yet). MVC doesn't support Session variables or Cookies, which are implemented via session variables. Global variables will be set for ALL users, which is not how Session variables work.
However, you can store "session variables" based on the User.Identity.Name or the underlying User.Identity.Claims.AspNet.Identity.SecurityStamp into a database along with a timestamp and viola! You have implemented primitive session variables. I had a very specific need to save two weeks of programming by not interfering with the GUI that our user interface specialist had written. So I returned NoContent() instead of the normal View() and I saved my hacky session variable based on the user's login name.
Am I recommending this for most situations? No. You can use ViewBag or return View(model) and it will work just fine. But if you need to save session variables in MVC for whatever reason, this code works. The code below is in production and works.
To retrieve the data...
string GUID = merchdata.GetGUIDbyIdentityName(User.Identity.Name);
internal string GetGUIDbyIdentityName(string name)
{
string retval = string.Empty;
try
{
using (var con = new SqlConnection(Common.DB_CONNECTION_STRING_BOARDING))
{
con.Open();
using (var command = new SqlCommand("select GUID from SessionVariablesByIdentityName md where md.IdentityName = '" + name + "' and LastSaved > getdate() - 1", con))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
retval = reader["GUID"].ToString();
}
}
}
}
}
catch (Exception ex)
{
}
return retval;
}
To save the data...
merchdata.SetGUIDbyIdentityName(User.Identity.Name, returnedGUID);
internal void SetGUIDbyIdentityName(string name, string returnedGUID)
{
RunSQL("exec CRUDSessionVariablesByIdentityName #GUID='" + returnedGUID + "', #IdentityName = '" + name + "'");
}
internal void RunParameterizedSQL(SqlConnection cn, SqlCommand cmd, object sqlStr)
{
string retval = string.Empty;
try
{
cn.Open();
cmd.ExecuteNonQuery();
cn.Close();
}
BTW: The SQL table (named SessionVariablesByIdentityName here) is fairly straightforward and can store lots of other things too. I have a LastSaved datetime field in there so I don't bother retrieving old data from yesterday. For example.
Perhaps I'm missing something, or perhaps .NET is missing something (preferably the former)
When building an application (not exclusively ASP.NET, but such is my situation; specifically an ASP.NET hosted WCF DS) it seems there's no native way to create a NetworkCredential object from an HttpRequest, or any similar request/header container,.
Do we always have to roll our own, or is there some magic tucked away in System.Net.* or System.Web.* with a signature like:
NetworkCredential GetAuthorization(HttpRequest request);
It's trivial I know, but I would assume something standard to the HTTP architecture would be included in something that is otherwise so encompassing (.NET)
So, home-brew string manipulation, or magic method hiding somewhere?
I don't think there's anything built-in; it would be of limited use, since most clients use Kerberos or Digest authentication instead.
However, it's fairly simple to roll your own:
static NetworkCredential ParseBasicAuthorizationHeader(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return null;
}
if (!value.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase))
{
return null;
}
byte[] data = Convert.FromBase64String(value.Substring(6));
value = Encoding.GetEncoding("ISO-8859-1").GetString(data);
int index = value.IndexOf(':');
if (index == -1 || index == 0 || index == value.Length - 1)
{
return null;
}
return new NetworkCredential(
value.Substring(0, index), // Username
value.Substring(index + 1)); // Password
}
Bear in mind that, like all other HTTP headers, the Authorization header is completely controlled by the client, and should therefore be treated as untrusted user input.
I am attempting to implement multi-tenancy in a legacy ASP.NET WebForms app. I want the URL to indicate the proper client, like so:
http://example.com/client_name/Default.aspx
http://example.com/client_name/MyWebService.asmx
However, I cannot get it to route the .asmx's properly. This routing rule picks up all incoming urls just fine:
routes.Add("ClientSelector", new System.Web.Routing.Route
(
"{client}/{*path}",
routeHandler: new ClientRoute()
));
But I am having issues with handling .asmx calls. Here's my IRouteHandler, below. The error I get is:
A first chance exception of type 'System.Web.Services.Protocols.SoapException' occurred in System.Web.Services.dll
Additional information: Unable to handle request without a valid action parameter. Please supply a valid soap action.
It's supposed to be JSON, but for some reason it's not working. I am setting the content-type - if I send this same exact request without routing, it works fine.
public class ClientRoute : System.Web.Routing.IRouteHandler
{
private string m_Path;
private string m_Client;
public ClientRoute() { }
public bool IsReusable { get { return true; } }
public IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
{
this.m_Path = (string)requestContext.RouteData.Values["path"];
this.m_Client = (string)requestContext.RouteData.Values["client"];
string virtualPath = "~/" + this.m_Path;
bool shouldValidate = false;
if (shouldValidate && !UrlAuthorizationModule.CheckUrlAccessForPrincipal(
virtualPath, requestContext.HttpContext.User,
requestContext.HttpContext.Request.HttpMethod))
{
requestContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
requestContext.HttpContext.Response.End();
return null;
}
else
{
HttpContext.Current.RewritePath(virtualPath);
HttpContext.Current.Items.Add("Client", this.m_Client);
if (virtualPath.EndsWith(".aspx"))
return (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page));
else
{
var asmxPos = virtualPath.IndexOf(".asmx", StringComparison.OrdinalIgnoreCase);
if (asmxPos >= 0)
{
// What goes here? This isn't working...
var asmxOnlyVirtualPath = virtualPath.Substring(0, asmxPos + 5);
return new System.Web.Services.Protocols.WebServiceHandlerFactory().GetHandler(
HttpContext.Current, HttpContext.Current.Request.HttpMethod, asmxOnlyVirtualPath, HttpContext.Current.Server.MapPath(asmxOnlyVirtualPath));
}
else
return new StaticRoute();
}
}
}
}
Relevant links:
Getting ScriptHandlerFactory handler
The open source http://www.teamlab.com project is built with ASP.NET Webforms, and uses a multitenant/saas model. I noticed you posted another question inquiring about multitenancy.
Perhaps you can look into their code for reference ideas.
I tried my best, ended up failing, and converted all my web services to WCF .svc services instead.
I have web service asp.Net and i want only one specific web application uses it, but I can't do this .
can any one tell me how i can solve this problem .
If you know the IP address of the only computer that is allowed to use your webservice, you can check for it and either return a 404 or an exception if it isn't.
Authentication solution
You can protect your methods by using the password as the argument in each of them, or in a better scenario use traditional forms authentication to authorize user (in this case your application) and then check if the user is logged while invoking webmethods.
For example crate authorize method like this:
[WebMethod(EnableSession = true)]
public bool Authorize(login, password)
{
if(login == "admin" && password == "supersecret")
{
FormsAuthentication.SetAuthCookie(login, false);
return true;
}
return false;
}
[WebMethod(EnableSession = true)
public string SomeWebMethod()
{
if(!User.Identity.IsAuthenticated)
throw Exception("User unathenticated");
/* method body */
}
Then you can use your webservice by invoking Authorize method just once at the start of using it, and then use all methods you like because authentication info is stored in the webservice providing server session.
Do not forget to set EnableSession to true in all your webmethods.
IP comparing solution
In your webservice put a method
public bool CanExecute()
{
return Context.Request.UserHostAddress == "290.110.11.12" /* put real ip here */
}
then in your webmethods use
[WebMethod(EnableSession = true)
public string SomeWebMethod()
{
if(!CanExecute())
throw Exception("User unathenticated");
/* method body */
}
Hope this helps :)