Static methods in asp.net mvc - asp.net-mvc

using asp.net mvc 4,
I created a class with a static method like this
public class StaticClass
{
public static int val { get; set; }
public static string ReturnValueBasedOnInput(int n)
{
string res;
switch (n)
{
case 101:
Thread.Sleep(30000);
res = "Long lasting response: 101" + val;
break;
default:
res = n.ToString() + " was provided..." + val;
break;
}
return res;
}
}
it is called from my controller :
public ActionResult Index(int id = 1)
{
ViewBag.returnValue = StaticClass.ReturnValueBasedOnInput(id);
return View(id);
}
I expected that when i call the method with a parameter value of 101 the application should be blocked for 30 secs, but it remains responsive. I thought since this is a static method it should be blocked for 30 second for all incoming method calls. can someone explain what happens here?

The thread handling the request to the Index action with id=101 of your controller should be blocked. Threads handling other requests of other sessions will not be blocked. Even other requests for the same session may not be blocked depending on ReadOnly session attribute of corresponding controllers [SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)].

Related

consuming REST service, method returning multiple types .. what to do

I am consuming someone elses REST service for my app. the problem is that each request can return 1 of 3 different types when responding
either:
the expected successfull response type
an error response which wraps the 500 (Error)
a validation error response (ValidationErrors)
I am currently calling the service wrapping each request with a class like this:
public class ApiResponse<T>
{
public T ResponseObject { get; set; }
public ValidationErrors<ValidationError> Errors { get; set; }
public Error Error { get; set; }
}
public async Task<ApiResponse<AMethodResponse>> AMethod(AMethodRequest req)
{
ApiResponse<AMethodResponse> resp = new ApiResponse<AMethodResponse> { Errors = new ValidationErrors<ValidationError>() };
using (HttpClient client = HttpClientFactory.Create(new AuthorisationHandler(), new ContentTypeHandler()))
{
client.BaseAddress = new Uri(BaseURI);
var httpResponseMessage = await client.PostAsXmlAsync<AMethodRequest>("AMethod/", req);
if (!httpResponseMessage.IsSuccessStatusCode)
{
//its at this point that I need to work out if i am getting Validation Errors or.. a plain Error
//I can do this, but of course if its a plain error it will fall over
resp.Errors = await httpResponseMessage.Content.ReadAsAsync<ValidationErrors<ValidationError>>();
}
else
{
resp.ResponseObject = await httpResponseMessage.Content.ReadAsAsync<AMethodResponse>();
}
}
return resp;
}
I wonder if there is a more reliable pattern to writing consuming methods.
thanks
it gives a 200 for all is well. 400 for validationerror and 500 for a real error
Check the status code directly, rather than use IsSuccessStatusCode :
var httpResponseMessage = await client.PostAsXmlAsync<AMethodRequest>("AMethod/", req);
switch (httpResponseMessage.StatusCode)
{
case HttpStatusCode.OK: //200
resp.ResponseObject = await httpResponseMessage.Content.ReadAsAsync<AMethodResponse>();
break;
case HttpStatusCode.BadRequest: //400
resp.Errors = await httpResponseMessage.Content.ReadAsAsync<ValidationErrors<ValidationError>>();
break;
case HttpStatusCode.InternalServerError: //500
throw new Exception("failed"); // use appropriate exception and/or read 500 wrapper
break;
}
return resp;

Read and write cookies with #Push

In my vaadin application, i need to use #Push, but since i added it, i can't read and write cookies because VaadinService.getSurrentResponse()returns null because of Push. I manager cookies using this class :
import javax.servlet.http.Cookie;
import com.vaadin.server.VaadinResponse;
import com.vaadin.server.VaadinService;
public class CookieManager {
private VaadinResponse response;
public CookieManager(VaadinResponse response){
this.response = response;
}
public Cookie getCookieByName(final String name) {
// Fetch all cookies from the request
Cookie[] cookies = VaadinService.getCurrentRequest().getCookies();
// Iterate to find cookie by its name
for (Cookie cookie : cookies) {
if (name.equals(cookie.getName())) {
return cookie;
}
}
return null;
}
public Cookie createCookie(final String name, final String value, final int maxAge) {
// Create a new cookie
final Cookie cookie = new Cookie(name, value);
cookie.setMaxAge(maxAge);
// Set the cookie path.
cookie.setPath(VaadinService.getCurrentRequest().getContextPath());
// Save cookie
addCookie(cookie);
return cookie;
}
private void addCookie(Cookie cookie){
response.addCookie(cookie);
}
public Cookie updateCookieValue(final String name, final String value) {
// Create a new cookie
Cookie cookie = getCookieByName(name);
cookie.setValue(value);
// Save cookie
addCookie(cookie);
return cookie;
}
public void destroyCookieByName(final String name) {
Cookie cookie = getCookieByName(name);
if (cookie != null) {
cookie.setValue(null);
// By setting the cookie maxAge to 0 it will deleted immediately
cookie.setMaxAge(0);
cookie.setPath(VaadinService.getCurrentRequest().getContextPath());
addCookie(cookie);
}
}
}
When i want to create a cookie (like at user's login), i get a nullPointerException because of the VaadinResponse being null.
So i tried to disable Push in constructor and re-enable it at the end of addCookie()method, but it disabled push for all of my application, even if i re-enable it just after the addCookiemethod.
I saw a ticket on vaadin's trac (http://dev.vaadin.com/ticket/11808) saying that will not be fixed, and someone suggested to create a regular AJAX query from server to create cookie, but i really don't know how to do.
How can i manage my cookies? i need to create AND get cookies, so javascript can't help me there, because i can't get javascript's return in vaadin, so i can't get a cookie.
Here is my solution how to store cookie when #Push is using.
First we create container to storage all instance of client UI. (
This container itself has a great potential)
public class UISession {
private List<WebAppUI> uis = new ArrayList<WebAppUI>();
public void addUI(WebAppUI webAppUI) {
uis.add(webAppUI);
}
public List<WebAppUI> getUIs() {
return uis;
}
public static UISession getInstance() {
try {
UI.getCurrent().getSession().lock();
return (UISession) UI.getCurrent().getSession().getAttribute("userUiSession");
} finally {
UI.getCurrent().getSession().unlock();
}
}
In UI.init() we add new instance to the session (e.g when user open new tab)
#Override
protected void init(VaadinRequest vaadinRequest) {
/** Set singleton uisesison for each browser*/
if(UISession.getInstance()==null){
UI.getCurrent().getSession().setAttribute("userUiSession",new UISession());
}
UISession.getInstance().addUI(this);
System.out.println("UI count fo current browser "+UISession.getInstance().getUIs().size());
...
}
Here is my helper cookie class:
class MyCookie{
private String value;
private String name;
private Date expired;
private String path="/";
public MyCookie(String name, String value) {
this.name=name;
this.value=value;
}
public void setMaxAge(int minute) {
Calendar c = Calendar.getInstance();
c.add(Calendar.MINUTE, minute);
expired=c.getTime();
}
public String getStringToCreateCookie(){
return "document.cookie=\""+getName()+"="+getValue()+"; expires="+expired.toString()+"; path="+path+"\"";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Date getExpired() {
return expired;
}
public void setExpired(Date expired) {
this.expired = expired;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
And on final when we need add new cookie, we just must find Ui that is active and call js function
public static void addCookie(String name, String value, int age){
MyCookie myCookie = new MyCookie(name, value);
myCookie.setMaxAge(age);
for(WebAppUI ui : UISession.getInstance().getUIs()){
if(ui.isAttached()){
ui.getPage().getJavaScript().execute(myCookie.getStringToCreateCookie());
return;
}
}
}
In my case i have access to storage cookie (when user made request). I just only have problem with add new cookie so this is my working solutions.
As mentioned in the ticket, you can use JavaScript to call client code and also request a cookie value back by that. E.g.
#Grapes([
#Grab('org.vaadin.spring:spring-boot-vaadin:0.0.3'),
#Grab('com.vaadin:vaadin-server:7.4.0.beta1'),
#Grab('com.vaadin:vaadin-client-compiled:7.4.0.beta1'),
#Grab('com.vaadin:vaadin-themes:7.4.0.beta1'),
])
import com.vaadin.ui.*
#org.vaadin.spring.VaadinUI
#groovy.transform.CompileStatic
class MyUI extends UI {
protected void init(com.vaadin.server.VaadinRequest request) {
final resultLabel = new Label()
// provide a callback for the client to tell the cookies
JavaScript.current.addFunction("tellCookie", { elemental.json.JsonArray arguments ->
resultLabel.value = arguments?.get(0)?.asString()
} as JavaScriptFunction)
setContent(new VerticalLayout().with{
addComponent(new Button("Set Cookie", {
// just simply set the cookies via JS (attn: quoting etc)
JavaScript.current.execute("document.cookie='mycookie=${System.currentTimeMillis()}'")
} as Button.ClickListener))
addComponent(new Button("Get Cookie", {
// tell the client to tell the server the cookies
JavaScript.current.execute("this.tellCookie(document.cookie)")
} as Button.ClickListener))
addComponent(resultLabel)
return it
})
}
}
This is a running example (e.g. spring run vaadin.groovy) for testing. See the comments for the important parts.
The Viritin add-on contains a helper class called BrowserCookie. It works in pretty much the way suggested by cfrick, but just hides all the cookie handling complexity into a helper class. It don't contain built in "max age" handling yet, but that could be easily added as a workaround you can manually "encode" the age into cookie value.
BTW. Don't know what you are doing, but if you happen to be using TouchKit add-on, it has a helper for html5 local storage. It has rather wide browsers support already and is in many ways better way to store e.g. settings than cookies.

How to pass value from one action to another action having same controller

Hi I am developing an application in MVC3. and i am stuck at one place. Everytime when control goes to IIndex1 action its argument value has become 0. But it should be same as value in IIndex action argument. I have used session, ViewBag, ViewData but my problem is remains. Please suggest me.
public ActionResult GetMDN(string msisdn)
{
number = msisdn.Substring(0, msisdn.IndexOf('$'));
if (number.ToLower() != "unknown" && number.Length == 12)
{
number = number.Remove(0, 2);
}
Session["msdresponse"] = number;
Session["moptr"] = msisdn.Substring(msisdn.LastIndexOf('$') + 1);
number = msisdn;
int sngid=int.Parse(ViewData["isongid"].ToString());
return RedirectToAction("IIndex1", new { iid = sngid });
}
public ActionResult IIndex(int id)
{
ViewBag.isongid = id;
ViewData["isongid"] = id;
Response.Redirect("http:XXXXXXXXXXXXXXXX");
return RedirectToAction("GetMDN");
}
public ActionResult IIndex1(int iid)
{
}
You can use TempData.You can pass every types of data between to action, whether they are in same controller or not. Your code should be something like it:
public ActionResult GetMDN(string msisdn)
{
int sngid=10;
TempData["ID"] = sngid;
return RedirectToAction("IIndex");
}
public ActionResult IIndex()
{
int id = Convert.ToInt32(TempData["ID"]);// id will be 10;
}
Use TempData instead of ViewData/ViewBag to store data that should persist after redirect.
ViewData/ViewBag allow to pass value from controller to view.
Something to read on this subject:
http://www.codeproject.com/Articles/476967/WhatplusisplusViewData-cplusViewBagplusandplusTem
http://msdn.microsoft.com/en-us/library/dd394711(v=vs.100).aspx
you can use TempData["name"] = variableToPass;

MVC AsyncController Blocking

So I've been following along with Steven Sanderson's TechDays Talk on SignalR and ASP.NET Async. I've run into a problem with the following actions
public class SomeController : AsyncController
{
static TaskCompletionSource<String> _nextMessage
= new TaskCompletionSource<string>();
[HttpPost]
public ActionResult PostMessage(string message)
{
_nextMessage = new TaskCompletionSource<string>();
oldNextMessage.SetResult(message);
return Content("success");
}
public async void GetMessages()
{
Response.ContentType = "text/event-stream";
while (true)
{
var message = await _nextMessage.Task;
Response.Write("data: " + message + "\n\n");
Response.Flush();
}
}
}
GetMessages seems to be blocking when it is first called, but once it times out, it starts working as expected.
So I load up my javascript which posts and runs GetMessages. On the first call to GetMessages, it hangs (as expected) at
await _nextMessage.Task;
but it won't let me make a call to PostMessage from any where (including other instances of the browser) This is on my dev machine, so it may be a thread issue, but I thought the whole purpose of this was to allow threads to work on multiple things. And that's besides the point that after it times out the first time, it starts to work as expected, where I can post, and get responses immediately. But if I refresh the page, I get the same problem. Any ideas on how to fix this? I'm using Eventsource by the way, but the same problem occurs when I'm doing long polling e.g.
public async Task<string> GetNextMessage()
{
return await _nextMessage.Task;
}
with a javascript loop function calling GetNextMessage()
Here's what I wound up using
[SessionState(SessionStateBehavior.Disabled)]
public class SomeController : AsyncController
{
    static TaskCompletionSource<String> _nextMessage =
new TaskCompletionSource<string>();
public void PostMessage(string message)
{
var CreationJObj = FormUtils.AsciiToJObject(Request.Form[0]);
var CreationObj = FormUtils.FromJObject<MessageDisplayVO>(CreationJObj);
Parallel.Invoke(() => { _nextMessage.SetResult(CreationObj.Message); });
_nextMessage = new TaskCompletionSource<string>();
}
public async void GetMessages()
{
Response.ContentType = "text/event-stream";
var oldMessage = _nextMessage;
var message = await oldMessage.Task;
Response.Write("data: " + message + "\n\n");
Response.Flush();
}
}

Session Variables Lost Between Controllers & Action Methods

I have almost exactly the same scenario described by Nathon Taylor in ASP.NET MVC - Sharing Session State Between Controllers. The problem is that if I save the path to the images inside a Session variable List<string> it is not being defined back in the ItemController so all the paths are being lost... Here's my setup:
Inside ImageController I have the Upload() action method:
public ActionResult Upload()
{
var newFile = System.Web.HttpContext.Current.Request.Files["Filedata"];
string guid = Guid.NewGuid() + newFile.FileName;
string itemImagesFolder = Server.MapPath(Url.Content("~/Content/ItemImages/"));
string fileName = itemImagesFolder + "originals/" + guid;
newFile.SaveAs(fileName);
var resizePath = itemImagesFolder + "temp/";
string finalPath;
foreach (var dim in _dimensions)
{
var resizedPath = _imageService.ResizeImage(fileName, resizePath, dim.Width + (dim.Width * 10/100), guid);
var bytes = _imageService.CropImage(resizedPath, dim.Width, dim.Height, 0, 0);
finalPath = itemImagesFolder + dim.Title + "/" + guid;
_imageService.SaveImage(bytes, finalPath);
}
AddToSession(guid);
var returnPath = Url.Content("~/Content/ItemImages/150x150/" + guid);
return Content(returnPath);
}
private void AddToSession(string fileName)
{
if(Session[SessionKeys.Images] == null)
{
var imageList = new List<string>();
Session[SessionKeys.Images] = imageList;
}
((List<string>)Session[SessionKeys.Images]).Add(fileName);
}
Then inside my ItemController I have the New() action method which has the following code:
List<string> imageNames;
var images = new List<Image>();
if (Session[SessionKeys.Images] != null) //always returns false
{
imageNames = Session[SessionKeys.Images] as List<string>;
int rank = 1;
foreach (var name in imageNames)
{
var img = new Image {Name = name, Rank = rank};
images.Add(img);
rank++;
}
}
Ok so why is this happening and how do I solve it?
Also, I was thinking of whether I could move the ActionMethod that takes care of the upload of the images into the ItemController and store the image paths inside a List property on the ItemController itself, would that actually work? Note though, that images are being uploaded and taken care of via an AJAX request. Then when the user submits the item entry form, all the data about the Item along with the images should be saved to the database...
Update:
I've updated the code. Also I think I should add that I'm using StructureMap as my controller factorory. Could it be a scoping issue? What is the default scope that is usually used by StructureMap?
public class StructureMapDependencyResolver : IDependencyResolver
{
public StructureMapDependencyResolver(IContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
if (serviceType.IsAbstract || serviceType.IsInterface)
{
return _container.TryGetInstance(serviceType);
}
else
{
return _container.GetInstance(serviceType);
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAllInstances<object>()
.Where(s => s.GetType() == serviceType);
}
private readonly IContainer _container;
}
And inside my Global.asax file:
private static IContainer ConfigureStructureMap()
{
ObjectFactory.Configure(x =>
{
x.For<IDatabaseFactory>().Use<EfDatabaseFactory>();
x.For<IUnitOfWork>().Use<UnitOfWork>();
x.For<IGenericMethodsRepository>().Use<GenericMethodsRepository>();
x.For<IUserService>().Use<UsersManager>();
x.For<IBiddingService>().Use<BiddingService>();
x.For<ISearchService>().Use<SearchService>();
x.For<IFaqService>().Use<FaqService>();
x.For<IItemsService>().Use<ItemsService>();
x.For<IMessagingService>().Use<MessagingService>();
x.For<IStaticQueriesService>().Use<StaticQueriesService>();
x.For < IImagesService<Image>>().Use<ImagesService>();
x.For<ICommentingService>().Use<CommentingService>();
x.For<ICategoryService>().Use<CategoryService>();
x.For<IHelper>().Use<Helper>();
x.For<HttpContext>().HttpContextScoped().Use(HttpContext.Current);
x.For(typeof(Validator<>)).Use(typeof(NullValidator<>));
x.For<Validator<Rating>>().Use<RatingValidator>();
x.For<Validator<TopLevelCategory>>().Use<TopLevelCategoryValidator>();
});
Func<Type, IValidator> validatorFactory = type =>
{
var valType = typeof(Validator<>).MakeGenericType(type);
return (IValidator)ObjectFactory.GetInstance(valType);
};
ObjectFactory.Configure(x => x.For<IValidationProvider>().Use(() => new ValidationProvider(validatorFactory)));
return ObjectFactory.Container;
}
Any thoughts?
I just added this to Global.asax.cs
protected void Session_Start()
{
}
It seems that this fixed the issue. I set a breakpoint that gets hit only once per session (as expected).
One possible reason for this is that the application domain restarts between the first and the second actions and because session is stored in memory it will be lost. This could happen if you recompile the application between the two. Try putting a breakpoints in the Application_Start and Session_Start callbacks in Global.asax and see if they are called twice.
Are you ever using it other than accessing HttpContext.Current directly in your code? In other words, are there any places where you're injecting the HttpContext for the sake of mocking in unit tests?
If you're only accessing it directly in your methods, then there's no reason to have the entry x.For<HttpContext>().HttpContextScoped().Use(HttpContext.Current); in you application startup. I wonder if it would start working if you removed it.

Resources