I'm upgrading an old application in asp net mvc to a new version with asp core + angular 7. In the old app, we had an external service calling our api, and sending the auth token in the URL because it couldn't do otherwise.
I intercept it to inject the token in the header like this:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_PreSendRequestHeaders()
{
Response.Headers.Remove("X-Frame-Options");
Response.AddHeader("X-Frame-Options", "AllowAll");
}
private void Application_BeginRequest(object sender, EventArgs e)
{
var header = HttpContext.Current.Request;
var url = HttpContext.Current.Request.Url;
var Params = HttpContext.Current.Request.Params;
if (ReferenceEquals(null, HttpContext.Current.Request.Headers["Authorization"]))
{
var token = HttpContext.Current.Request.Params["access_token"];
if (!String.IsNullOrEmpty(token))
{
HttpContext.Current.Request.Headers.Add("Authorization", "Bearer " + token);
}
}
}
protected void Application_Start()
{
//DashboardConfig.RegisterService(RouteTable.Routes);
DevExtremeBundleConfig.RegisterBundles(BundleTable.Bundles);
C_Interface_Meta.IntialiserBdd();
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new RazorViewEngine());
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
//GlobalConfiguration.Configure(WebApiConfig.Register);
ASPxWebControl.CallbackError += Application_Error;
BundleConfig.RegisterBundles(BundleTable.Bundles);
DisableApplicationInsightsOnDebug();
}
/// <summary>
/// Disables the application insights locally.
/// </summary>
[Conditional("DEBUG")]
private static void DisableApplicationInsightsOnDebug()
{
TelemetryConfiguration.Active.DisableTelemetry = true;
}
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new PrettyPrintFilterAttribute());
}
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = HttpContext.Current.Server.GetLastError();
if (exception is HttpUnhandledException)
exception = exception.InnerException;
AddToLog(exception.Message, exception.StackTrace);
}
public static void AddToLog(string message, string stackTrace)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(DateTime.Now.ToLocalTime().ToString());
sb.AppendLine(message);
sb.AppendLine();
sb.AppendLine("Source File: " + HttpContext.Current.Request.RawUrl);
sb.AppendLine();
sb.AppendLine("Stack Trace: ");
sb.AppendLine(stackTrace);
for (int i = 0; i < 150; i++)
sb.Append("-");
sb.AppendLine();
HttpContext.Current.Application["Log"] += sb.ToString();
sb.AppendLine();
}
}
What is the equivalent way for doing that in an angular asp core application? After much searching, I didn't find anything.
Sounds like you're using JWT bearer and sending the token via query string. If that's the case, you could simply use an event handler OnMessageReceived to set the token dynamically :
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options=> {
options.TokenValidationParameters = new TokenValidationParameters{
// ValidIssuer, ValidAudience, IssuerSigningKey , ...
};
options.Events = new JwtBearerEvents() {
OnMessageReceived = async (context) =>{
// get bearer From Header/QueryString as you like
var bearer=context.HttpContext.Request.Query["access_token"].FirstOrDefault();
if(!String.IsNullOrEmpty(bearer)){
context.Token = bearer; // simply set the token
}
},
};
});
// other services ...
}
Or as suggested by Razgort, you could register a middleware to set the token.
Be careful for the order of middlewares.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// register it before other middlewares that rely on this token
app.Use(async(context,next)=>{
var bearer = context.Request.Headers["Authorization"].FirstOrDefault();
if(bearer==null){
bearer=context.Request.Query["access_token"].FirstOrDefault();
if(!String.IsNullOrEmpty(bearer)){
context.Request.Headers.Add("Authorization", "Bearer " + bearer);
}
}
await next();
});
// other middlewares ...
app.UseMvc(...)//
}
I think you are looking for angular interceptors, which pretty much doest the same thing. You want to inject the tokens something like this:
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private auth: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
// Get the auth token from the service.
const authToken = this.auth.getAuthorizationToken();
// Clone the request and replace the original headers with
// cloned headers, updated with the authorization.
const authReq = req.clone({
headers: req.headers.set('Authorization', authToken)
});
// send cloned request with header to the next handler.
return next.handle(authReq);
}
}
Related
I am trying to authorize the swagger api with the okta configuration using ASP.NET core 2.2.
Followed the instruction from this link
https://app.swaggerhub.com/help/enterprise/user-management/sso/okta
But quite not sure how can I do it.
Okta link
https://developer.okta.com/quickstart/?_ga=2.180885607.1554519477.1569975022-1481902663.1569975022#/angular/dotnet/aspnetcore
here is my Asp.net code
ConfigureSwagger(services);
protected virtual void ConfigureSwagger(IServiceCollection services)
{
// to view online help, goto ~/swagger/
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
services.AddSwaggerGen(options =>
{
// add a custom operation filter which sets default values
options.OperationFilter<SwaggerDefaultValues>();
});
services.ConfigureSwaggerGen(options => { });
}
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
{
readonly IApiVersionDescriptionProvider provider;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigureSwaggerOptions"/> class.
/// </summary>
/// <param name="provider">The <see cref="IApiVersionDescriptionProvider">provider</see> used to generate Swagger documents.</param>
public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) => this.provider = provider;
/// <inheritdoc />
public void Configure(SwaggerGenOptions options)
{
// add a swagger document for each discovered API version
// note: you might choose to skip or document deprecated API versions differently
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description));
}
options.OrderActionsBy(apiDesc => apiDesc.RelativePath);
options.IncludeXmlComments(Path.ChangeExtension(typeof(Startup).GetTypeInfo().Assembly.Location, "xml"));
options.DescribeAllEnumsAsStrings();
options.DescribeStringEnumsInCamelCase();
//options.AddSecurityDefinition("oauth2",
// new OAuth2Scheme
// {
// Type = "oauth2",
// Flow = "implicit",
// AuthorizationUrl = new Uri("/connect/authorize", UriKind.Relative).ToString(),
// Scopes = new Dictionary<string, string>
// {
// {"api1", "DEMO API"}
// }
// });
//options.AddSecurityRequirement(new[] { "oauth2", "api1" });
options.AddSecurityDefinition("oauth2",
new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
Implicit = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri("/connect/authorize", UriKind.Relative),
Scopes = new Dictionary<string, string>
{
{Program.ResourceIdentifier, Program.ApplicationName}
}
}
}
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2"
}
},
new[] {"oauth2", Program.ResourceIdentifier }
}
});
options.EnableAnnotations();
//options.DocInclusionPredicate((docName, apiDesc) =>
//{
// if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo)) return false;
// var versions = methodInfo.DeclaringType
// .GetCustomAttributes(true)
// .OfType<ApiVersionAttribute>()
// .SelectMany(attr => attr.Versions);
// return versions.Any(v => $"v{v.ToString()}" == docName);
//});
}
static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description)
{
var info = new OpenApiInfo
{
Title = Program.ApplicationName,
Version = $"v{description.ApiVersion}",
Description = "A sample application with Swagger, Swashbuckle, and API versioning."
};
if (description.IsDeprecated)
{
info.Description += " This API version has been deprecated.";
}
return info;
}
}
public static void UseSwaggerMiddleware(this IApplicationBuilder app, IApiVersionDescriptionProvider provider)
{
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
// build a swagger endpoint for each discovered API version
foreach (var description in provider.ApiVersionDescriptions)
{
c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
//OAuth2
c.OAuthClientId("{clientId}");
//c.OAuth2RedirectUrl("");
//c.OAuthUseBasicAuthenticationWithAccessCodeGrant();
c.OAuthClientSecret("{ClientSecret}");
c.OAuthAppName("{AppName}");
c.OAuthScopeSeparator("openid profile email");
c.OAuthAdditionalQueryStringParams(new Dictionary<string, string>
{
{ "response_type","token"}
});
});
}
Errors
Hide
Auth error
{"state":"VGh1IE9jdCAwMyAyMDE5IDE1OjI4OjEyIEdNVCsxMDAwIChBVVMgRWFzdGVybiBTdGFuZGFyZCBUaW1lKQ==","error":"unsupported_response_type","error_description":"The+response+type+is+not+supported+by+the+authorization+server.+Configured+response+types:+[id_token,+code]."}
How do I configure with swagger authorization client with JWT token.
Finally found the solution
Need to do this configuration on asp.net core
public static void UseSwaggerMiddleware(this IApplicationBuilder app, IApiVersionDescriptionProvider provider, IConfiguration Configuration)
{
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
// build a swagger endpoint for each discovered API version
foreach (var description in provider.ApiVersionDescriptions)
{
c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
//c.SwaggerEndpoint("/swagger/v2/swagger.json", "DEMO Api v2");
//c.SwaggerEndpoint("/swagger/v1/swagger.json", "DEMO Api v1");
//OAuth2
var OktaConfig = new OktaConfig();
Configuration.GetSection("OktaConfig").Bind(OktaConfig);
c.OAuthClientId(OktaConfig.ClientId);
c.OAuth2RedirectUrl($"{OktaConfig.RedirectUrl}/swagger/oauth2-redirect.html");
c.OAuthUseBasicAuthenticationWithAccessCodeGrant();
c.OAuthClientSecret(OktaConfig.ClientSecret);
c.OAuthAppName(OktaConfig.ClientName);
c.OAuthScopeSeparator($"openid profile email {Program.ResourceIdentifier}");
c.OAuthAdditionalQueryStringParams(new Dictionary<string, string>
{
{ "response_type","token"},
{ "nonce", "nonce" }
});
//c.ConfigObject.DeepLinking = true;
});
}
And need to add policies and rule
I have a Hub that works inside Visual Studio Community 2017 for ASP.Net Core & SignalR. Everything works beautifully as long as it runs under VS. I read what is available & am not getting any luck. I have a HostedService that on StartAsync kicks off a thread with the Background prop set to true. This thread reads from a socket & then calls SendMessage on the Hub. I'm not sure what I'm doing wrong. It publishes an exe, but it is not working.
I have read all that I can find. I added a Hosted Service that is added under Startup.
// STARTUP
public class cRioHubStartup {
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.AddMvc();
services.AddHostedService<cRioHubHostService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
string virtDir = cRioHubGlobals.getHubUrl().VirtualDirectory;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
//app.UseHsts();
}
app.UseDefaultFiles();
app.UseStaticFiles();
//app.UseCors(CorsOptions.AllowAll);
app.UseSignalR(routes =>
{
routes.MapHub<cRioHub>(virtDir);
});
app.UseMvc();
app.Run(async (context) =>
{
await context.Response.WriteAsync("cRioHub Started!");
});
}
/*
var hubContext = provider.GetService<IHubContext<cRioHub>>();
services.AddSingleton(provider =>
{
var hubContext = provider.GetService<IHubContext<cRioHub>>();
var update = new Update(hubContext);
return update;
});
*/
}
// HUB HOSTED SERVICE which kicks off background thread
public class cRioHubHostService : IHostedService, IDisposable
{
private static Thread _t = null;
public Thread thread
{
get { return _t; }
}
// Summary: Triggered when the application host is ready to start the service.
public Task StartAsync(CancellationToken cancellationToken)
{
_t = LaunchHub();
return Task.CompletedTask;
}
// Summary: Triggered when the application host is performing a graceful shutdown.
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public void Dispose()
{
_t = null;
}
public static Thread LaunchHub()
{
Object orfu = new object(); // saved for fut. use if needed
// set up hub
cRioHubConnection hub = new cRioHubConnection(cRioHubGlobals.getHubUrl(), cRioHubGlobals.getHubUrl().Name);
cRioHubGlobals.setHubConnection(new cRioHubConnection(hub));
//Globals.HubCnxn.SendMessage("Take2!");
// call thread to start TCP client wh. writes back to the hub on cRio msg. arrival
Thread t = new Thread(cRioHubTcpClient.cRioRunClient);
t.IsBackground = true;
t.Start(orfu);
return t;
}
public static void cRioRunClient(Object orfu)
{
string consMsg = "";
string urlHub = cRioHubGlobals.getHubUrl().makeUrl();
string urlCRio = cRioHubGlobals.getCRioUrl().makeUrl();
string fmtHubUrl = "Hub URL={0}" ;
string fmtCRioUrl = "cRio URL={0}";
consMsg = String.Format(fmtHubUrl, urlHub);
Console.WriteLine(consMsg);
consMsg = String.Format(fmtCRioUrl, urlCRio);
Console.WriteLine(consMsg);
cRioHubGlobals.setCRioTcpClient(new cRioHubTcpClient(orfu)); // gets its connection info from cRioHubGlobals
cRioHubGlobals.getCRioTcpClient().Message += (s, a) => Console.WriteLine("Client: " + a.Message);
Task clientTask = cRioHubGlobals.getCRioTcpClient().RunAsync();
Console.WriteLine("Program: Hit any char to stop.");
ConsoleEx.ReadChar();
cRioHubGlobals.getCRioTcpClient().Stop = true;
cRioHubGlobals.getCRioTcpClient().Dispose();
clientTask = null;
}
public static Task cRioStopClient()
{
Task tskHub = null;
cRioHubTcpClient client = cRioHubGlobals.getCRioTcpClient();
if (client != null)
{
client.Stop = true;
client.Dispose();
tskHub = cRioHubGlobals.getHubConnection().Stop();
}
Console.WriteLine("Stopping service!");
return tskHub;
}
The problem is the publisher with the appsettings & launch. If you choose a port other than the default 5000, it is not working. If you choose 5000, it works. This appears to be a bug.
I have implemented a subclass of AuthenticationHandler. It returns AuthenticationResult.Fail("This is why you can't log in");
I would have expected this message to end up in the body, or at least in the HTTP status text, but instead I get a blank 401 response.
Is there any way to provide additional information for failed authentication attempts in ASP.NET core?
Override HandleChallengeAsync:
In the example below the failReason is a private field in my implementation of AuthenticationHandler.
I don't know if this is the best way to pass the reason for failure. But the AuthenticationProperties on the AuthenticateResult.Fail method did not make it through to HandleChallengeAsync in my test.
public class CustomAuthenticationHandler<TOptions> : AuthenticationHandler<TOptions> where TOptions : AuthenticationSchemeOptions, new()
{
private string failReason;
public CustomAuthenticationHandler(IOptionsMonitor<TOptions> options
, ILoggerFactory logger
, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { }
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
failReason = "Reason for auth fail";
return AuthenticateResult.Fail(failReason);
}
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
Response.StatusCode = 401;
if (failReason != null)
{
Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = failReason;
}
return Task.CompletedTask;
}
}
From the docs: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.authenticationhandler-1?view=aspnetcore-2.2
Override this method to deal with 401 challenge concerns, if an authentication scheme in question deals an authentication interaction as part of it's request flow. (like adding a response header, or changing the 401 result to 302 of a login page or external sign-in location.)
Source:
https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication/AuthenticationHandler.cs#L201
I used this code in my custom Middleware to return problemDetails response.
public async Task Invoke(HttpContext httpContext)
{
await this.Next(httpContext);
if (httpContext.Response.StatusCode == StatusCodes.Status401Unauthorized)
{
var authenticateResult = await httpContext.AuthenticateAsync();
if (authenticateResult.Failure != null)
{
var routeData = httpContext.GetRouteData() ?? new RouteData();
var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor());
var problemDetails = this.ProblemDetailsFactory.CreateProblemDetails(httpContext,
statusCode: httpContext.Response.StatusCode,
detail: authenticateResult.Failure.Message);
var result = new ObjectResult(problemDetails)
{
ContentTypes = new MediaTypeCollection(),
StatusCode = problemDetails.Status,
DeclaredType = problemDetails.GetType()
};
await this.Executor.ExecuteAsync(actionContext, result);
}
}
}
For changing the body or Http status, you could try Context.Response.
Here is a demo code:
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace TestIdentity
{
public class CustomAuthenticationHandler<TOptions> : AuthenticationHandler<TOptions> where TOptions : AuthenticationSchemeOptions, new()
{
public CustomAuthenticationHandler(IOptionsMonitor<TOptions> options
, ILoggerFactory logger
, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
await Context.Response.WriteAsync("This is why you can't log in");
return AuthenticateResult.Fail("This is why you can't log in");
}
}
}
For the purpose of downloading files I need to use a GET: /API/File/ID?bearerToken=XYZ... method.
I've created a DelegatingHandler to add my token to the AuthorizationHeader, but it appears the token validation may be done before this point...
All of the tokens at current at added by Angular adding the token to the HTTP header before the request.
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
ConfigureOAuth(app);
WebApiConfig.Register(config);
GlobalFilters.Add(config);
app.UseWebApi(config);
config.MessageHandlers.Insert(0, new QueryStringBearerToken());
}
..
public class QueryStringBearerToken : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
var bearerToken = request.GetQueryNameValuePairs().
Where(kvp => kvp.Key == "bearertoken")
.Select(kvp => kvp.Value)
.FirstOrDefault();
//QueryString exists and Header doesn't
if (!string.IsNullOrWhiteSpace(bearerToken) && !request.Headers.Any(x=>x.Key == "Authorization"))
{
request.Headers.Add("Authorization", "Bearer " + bearerToken);
}
return base.SendAsync(request, cancellationToken);
}
}
I presume you are using Katana's Bearer middleware? (judging by your call to ConfigureAuth?)
If so, the Katana middleware will indeed run before the Web API handlers and reject your request before it even gets a chance to be processed by the handler.
Instead of creating a handler you should move your functionality to Katana middleware.
Here's an example:
public class QueryBearerMiddleware : OwinMiddleware
{
public QueryBearerMiddleware(OwinMiddleware next)
: base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
string bearerToken = null;
if (context.Request.QueryString.HasValue)
{
var queryPairs = context.Request.QueryString.ToUriComponent()
.Substring(1)
.Split(new [] {'&'}, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Split('=')).ToDictionary(x => x[0], x => x[1]);
if (queryPairs.ContainsKey("bearertoken"))
{
bearerToken = queryPairs["bearertoken"];
}
}
//QueryString exists and Header doesn't
if (!string.IsNullOrWhiteSpace(bearerToken) && context.Request.Headers.All(x => x.Key != "Authorization"))
{
context.Request.Headers.Add("Authorization", new [] { "Bearer " + bearerToken });
}
await Next.Invoke(context);
}
}
You should register this middleware to run before the Bearer middlware.
Somewhere in your ConfigureAuth you should have a call to app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());. This new middleware we just created, should be registered before, i.e:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use(typeof(QueryBearerMiddleware));
var config = new HttpConfiguration();
ConfigureOAuth(app);
WebApiConfig.Register(config);
GlobalFilters.Add(config);
app.UseWebApi(config);
}
}
a small but very annoying problem. I am trying to use jQuery JSON call with asp.net web service. It all works fine with the below HttpModule if I call the web service without any arguments. As soon as I try and send a value from the client side, Module gets executed but the process doesn't pass over to the actual webservice method and returns with a server side 500 error. If we remove the module from the middle, then the method gets executed perfectly fine with parameter but then the response comes back in the XML format instead of JSON so we are helpless to use the Module.
----------- Jquery Call ---------------------
var dd = { 'name': 'pakistan' };
$(document).ready(function () {
$.getJSON("http://localhost:59271/Testing/shows-app.asmx/HelloWorld?callback=?",
dd,
function (data) {
val = JSON.parse(data.d)
$("#content").html(val.response);
});
});
------------ HttpModule -------------
private const string JSON_CONTENT_TYPE = "application/json; charset=utf-8";
public void Dispose()
{
}
public void Init(HttpApplication app)
{
app.BeginRequest += OnBeginRequest;
app.EndRequest += new EventHandler(OnEndRequest);
}
public void OnBeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
HttpRequest request = app.Request;
//Make sure we only apply to our Web Service
if (request.Url.AbsolutePath.ToLower().Contains("-app."))
{
var method = app.Context.Request.Headers["REQUEST_METHOD"];
if (string.IsNullOrEmpty(app.Context.Request.ContentType))
{
app.Context.Request.ContentType = JSON_CONTENT_TYPE;
}
app.Context.Response.Write(app.Context.Request.Params["callback"] + "(");
var method2 = app.Context.Request.Headers["REQUEST_METHOD"];
}
}
void OnEndRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
HttpRequest request = app.Request;
if (request.Url.AbsolutePath.ToLower().Contains("-app."))
{
app.Context.Response.Write(")");
app.Context.Response.ContentType = "application/json";
}
}
----------- Webservice ---------------------
[WebMethod]
[System.Web.Script.Services.ScriptMethod(UseHttpGet = true, ResponseFormat = System.Web.Script.Services.ResponseFormat.Json)]
public string HelloWorld(string name)
{
var json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(new
{
response = "Pakistan " + " Zindabad"
});
return json;
//string jsoncallback = HttpContext.Current.Request["callback"];
//return string.Format("{0}({1})", jsoncallback, json);
}
Please remember that, if we remove the module from the middle, then the method gets executed perfectly fine with parameter but then the response comes back in the XML format instead of JSON so we are helpless to use the Module.
Thanks a bunch in advance.