how we can return a status code for the serialized JSON object using Newtonsoft.net - asp.net

I have this Action method which act as an API end point inside our ASP.NET MVC-5, where it search for a username and return the username Phone number and Department from Active Directory (we are serializing the object using Newtonsoft.net):-
public ActionResult UsersInfo2()
{
DomainContext result = new DomainContext();
try
{
// create LDAP connection object
DirectoryEntry myLdapConnection = createDirectoryEntry();
string ADServerName = System.Web.Configuration.WebConfigurationManager.AppSettings["ADServerName"];
string ADusername = System.Web.Configuration.WebConfigurationManager.AppSettings["ADUserName"];
string ADpassword = System.Web.Configuration.WebConfigurationManager.AppSettings["ADPassword"];
using (var context = new DirectoryEntry("LDAP://mydomain.com:389/DC=mydomain,DC=com", ADusername, ADpassword))
using (var search = new DirectorySearcher(context))
{
// create search object which operates on LDAP connection object
// and set search object to only find the user specified
// DirectorySearcher search = new DirectorySearcher(myLdapConnection);
// search.PropertiesToLoad.Add("telephoneNumber");
search.Filter = "(&(objectClass=user)(sAMAccountName=test.test))";
SearchResult r = search.FindOne();
ResultPropertyCollection fields = r.Properties;
foreach (String ldapField in fields.PropertyNames)
{
// cycle through objects in each field e.g. group membership
// (for many fields there will only be one object such as name)
string temp;
// foreach (Object myCollection in fields[ldapField])
// {
// temp = String.Format("{0,-20} : {1}",
// ldapField, myCollection.ToString());
if (ldapField.ToLower() == "telephonenumber")
{
foreach (Object myCollection in fields[ldapField])
{
result.Telephone = myCollection.ToString();
}
}
else if (ldapField.ToLower() == "department")
{
foreach (Object myCollection in fields[ldapField])
{
result.Department = myCollection.ToString();
}
}
// }
}
string output = JsonConvert.SerializeObject(result);
return Json(output,JsonRequestBehavior.AllowGet);
}
}
catch (Exception e)
{
Console.WriteLine("Exception caught:\n\n" + e.ToString());
}
return View(result);
}
now the return JSON will be as follow:-
"\"DisplayName\":null,\"Telephone\":\"123123\",\"Department\":\"IT\",\"Name\":null,\"SamAccountName\":null,\"DistinguishedName\":null,\"UserPrincipalName\":null}"
but in our case we need to return a status code beside the return json data. for example inccase there is an exception we need to return an error code,also if we are able to get the user's info we need to pass succes code 200, and so on.. so how we can achieve this?

you can try something like this
var statusCode=200;
string output = JsonConvert.SerializeObject( new { result = result, StatusCode = statusCode);
but nobody usually do this. When users call API they can check status code that HTTP Client returns, using code like this
var response = await client.GetAsync(api);
//or
var response = await client.PutAsJsonAsync(api, data);
var statusCode = response.StatusCode.ToString();
//or usually
if (response.IsSuccessStatusCode) {...}
else {...}

Related

Google.Apis.Requests.RequestError Not Found when deleting event

I have below method to delete event in calendar:
public async Task<string> DeleteEventInCalendarAsync(TokenResponse token, string googleUserId, string calendarId, string eventId)
{
string result = null;
try
{
if (_calService == null)
{
_calService = GetCalService(token, googleUserId);
}
// Check if event exist
var eventResource = new EventsResource(_calService);
var erListRequest = eventResource.List(calendarId);
var eventsResponse = await erListRequest.ExecuteAsync().ConfigureAwait(false);
var existingEvent = eventsResponse.Items.FirstOrDefault(e => e.Id == eventId);
if (existingEvent != null)
{
var deleteRequest = new EventsResource.DeleteRequest(_calService, calendarId, eventId);
result = await deleteRequest.ExecuteAsync().ConfigureAwait(false);
}
}
catch (Exception exc)
{
result = null;
_logService.LogException(exc);
}
return result;
}
And I am getting error as follow -
Google.GoogleApiException Google.Apis.Requests.RequestError Not Found [404] Errors [ Message[Not Found] Location[ - ] Reason[notFound] Domain[global] ]
Can you help me understand why this error? Or where I can find the details about these error?
The error you are getting is due to the event's id you are passing doesn't exist or you are passing it in the wrong way. Following the .Net Quickstart I made a simple code example on how to pass the event's id to the Delete(string calendarId, string eventId) method from the Class Events
namespace CalendarQuickstart
{
class Program
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/calendar-dotnet-quickstart.json
static string[] Scopes = { CalendarService.Scope.Calendar };
static string ApplicationName = "Google Calendar API .NET Quickstart";
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Google Calendar API service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Define request.
EventsResource.ListRequest request = service.Events.List("primary");
// List events.
Events events = request.Execute();
Event existingEvent = events.Items.FirstOrDefault(e => e.Id == "your event id you want to get");
Console.WriteLine("Upcoming events:");
if (existingEvent != null)
{
Console.WriteLine("{0} {1}", existingEvent.Summary, existingEvent.Id);
string deleteEvent = service.Events.Delete("primary", existingEvent.Id).Execute();
}
else
{
Console.WriteLine("No upcoming events found.");
}
Console.Read();
}
}
}
Notice
I made this example in a synchronous syntax way for testing purposes in the console. After you test it and see how it works, you could adapt it to your code. Remember, make your you are passing the correct Id.
Docs
For more info check this doc:
Namespace Google.Apis.Calendar.v3

Modify BuildApiResponse in ASP.Net Web Api

I am new in ASP.NET MVC Web API. I am trying to modified the return JSon to this format
{
"Error": false,
"Status": 200,
"Response": []
}
Now I able to do that by follow this post https://www.devtrends.co.uk/blog/wrapping-asp.net-web-api-responses-for-consistency-and-to-provide-additional-information . But the problem is I not able to show ModelState error like 'First name is required' because the code only show the first hit error.
if (error != null)
{
content = null;
//only show the first error
errorMessage = error.Message;
}
So I did some modification, now the code is written as below:
if (error != null)
{
content = null;
foreach(var e in error)
{
//if the error's type is ModelState
if (e.Key.Equals("ModelState"))
{
var allErrors = e.Value;
foreach (var modelError in (IEnumerable<KeyValuePair<string, object>>)allErrors)
{
var msg = modelError;
errorMessage = string.Concat(errorMessage, ", ", ((String[]) modelError.Value)[0]);
}
}
else
{
errorMessage = e.Value.ToString();
}
}
}
Now it's able to show all errors but the code is messy. I am writing this questions to find out what is the proper way to write this kind of code.
You can iterate over all the errors and concatenate them using StringBuilder. String.Join is much faster than Append for less than 1000 items (it is unlikely you will have so many errors in the modelstate object):
public static ValidationResult CheckValid(ModelStateDictionary modelState, string httpName = null)
{
if (!modelState.IsValid)
{
var sb = new StringBuilder();
sb.AppendLine(httpName + " failed: Invalid Json:");
foreach (var pair in modelState)
{
var error = String.Join(";", pair.Value.Errors.Select
(
i =>
{
if (!String.IsNullOrEmpty(i.ErrorMessage))
return i.ErrorMessage;
return i.Exception.Message;
}
));
sb.AppendLine($"Property: {pair.Key} Errors: ({error})");
}
return new ValidationResult(false, sb.ToString());
}
else
return new ValidationResult(true, "");
}

ASP.Net Core : get members of Active Directory group

I'm wondering how I could get a list of members of an AD group.
Checking if an entered password of a user is correct works perfectly fine. For this I'm using Novell's Ldap.NetStandard:
private bool IsUserValid(string userName,string userPassword)
{
try{
using (var connection = new LdapConnection { SecureSocketLayer = false })
{
connection.Connect("test.local", LdapConnection.DEFAULT_PORT);
connection.Bind(userDn, userPassword);
if (connection.Bound)
{
return true;
}
}
}
catch (LdapException ex)
{
Console.WriteLine(ex.Massage);
}
return false;
}
What I want now is something like this:
bool isUserInGroup("testUser","testGroup");
The problem is I can't get my method working:
public bool IsUserMemberOfGroup(string userName,string groupName)
{
var ldapConn = GetConnection();
var searchBase = "";
var filter = $"(&(objectClass=group)(cn={groupName}))";
var search = ldapConn.Search(searchBase, LdapConnection.SCOPE_BASE, filter, null, false);
while (search.hasMore())
{
var nextEntry = search.next();
if (nextEntry.DN == userName)
return true;
}
return false;
}
What ever I'm doing, I'm not getting back any value from my Ldap.Search()...
Now there is an implementation of System.DirectoryServices.AccountManagement for .NET Core 2. It is available via nuget.
With this package you are able to things like that:
using (var principalContext = new PrincipalContext(ContextType.Domain, "YOUR AD DOMAIN"))
{
var domainUsers = new List<string>();
var userPrinciple = new UserPrincipal(principalContext);
// Performe search for Domain users
using (var searchResult = new PrincipalSearcher(userPrinciple))
{
foreach (var domainUser in searchResult.FindAll())
{
if (domainUser.DisplayName != null)
{
domainUsers.Add(domainUser.DisplayName);
}
}
}
}
This performs a search for the user in your domain.Nearly the same is possible for searching your group. The way I used to search my AD (description in my question) is now obsolet:
Checking if an entered password of a user is correct works perfectly
fine. For this I'm using Novell's Ldap.NetStandard:
How about:
HttpContext.User.IsInRole("nameOfYourAdGroup");
(namespace System.Security.Claims)

what variable type I can use for response back from Web API

I call a web Api that is returning me back a response. at first I define the response as var but not I return to define the response at the top of the method. Ia m not sure what type of variable I have to use for it. I used dictionary but I am getting this is in new keyword.
cannot implicitly convert type 'AnonymousType#1' to Dictionary.
This is my code:
[AllowAnonymous]
[Route("searchuser")]
[HttpPost]
public async Task<ActionResult> SearchUser(UserInfo userInfo)
{
object userObject = null;
Dictionary<string, object> respone = new Dictionary<string, object>();
if (userInfo.LastName != null && userInfo.Zip != null && userInfo.Ssn != null)
{
UserKey userKey = new UserKey();
userKey.AccountKey = accessKey;
var response = await httpClient.PostAsJsonAsync(string.Format("{0}{1}", LoanApiBaseUrlValue, "/verifyuser"), userKey);
if (response.IsSuccessStatusCode)
{
userObject = new JavaScriptSerializer().DeserializeObject(response.Content.ReadAsStringAsync().Result) as object;
var json = response.Content.ReadAsStringAsync().Result;
var userVerify = new JavaScriptSerializer().Deserialize<VerifyUser>(json);
}
}
respone = new // this is where I am getting the error before I was using var and it was working.
{
success = userObject != null,
data = userObject
};
return Json(respone, JsonRequestBehavior.AllowGet);
}
Sending a result in JSON you can use any type of variable (List, Dictionary, int, string, ...).
You can do something like this:
public async Task<HttpResponseMessage> SearchUser(UserInfo userInfo) {
HttpResponseMessage response = new HttpResponseMessage();
try
{
object userObject = null;
// Do something
object result = new { success = userObject != null, data = userObject };
response = Request.CreateResponse(HttpStatusCode.OK, result);
}
catch (Exception e)
{
// Do Log
response = Request.CreateResponse(HttpStatusCode.BadRequest, e.Message);
}
var tc = new TaskCompletionSource<HttpResponseMessage>();
tc.SetResult(response);
return tc.Task;
}
And you'll have your return in JSON, regardless of the type of the variable, which in this case is an anonymous object type.
The error message "cannot implicitly convert type 'AnonymousType#1' to Dictionary." is because you are trying to set a value of anonymous object type to a variable of type Dictionary:
// ...
Dictionary<string, object> respone = new Dictionary<string, object>();
// ...
respone = new // this is where I am getting the error before I was using var and it was working.
{
success = userObject != null,
data = userObject
};

How to pass content in response from Exception filter in Asp.net WebAPI?

Consider following code:
My problem is:
1) I can't seem to cast the errors to HttpContent
2) I can't use the CreateContent extension method as this doesn't exist on the context.Response.Content.CreateContent
The example here only seems to provide StringContent and I'd like to be able to pass the content as a JsobObject:
http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling
public class ServiceLayerExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Response == null)
{
var exception = context.Exception as ModelValidationException;
if ( exception != null )
{
var modelState = new ModelStateDictionary();
modelState.AddModelError(exception.Key, exception.Description);
var errors = modelState.SelectMany(x => x.Value.Errors).Select(x => x.ErrorMessage);
// Cannot cast errors to HttpContent??
// var resp = new HttpResponseMessage(HttpStatusCode.BadRequest) {Content = errors};
// throw new HttpResponseException(resp);
// Cannot create response from extension method??
//context.Response.Content.CreateContent
}
else
{
context.Response = new HttpResponseMessage(context.Exception.ConvertToHttpStatus());
}
}
base.OnException(context);
}
}
context.Response = new HttpResponseMessage(context.Exception.ConvertToHttpStatus());
context.Response.Content = new StringContent("Hello World");
you also have the possibility to use the CreateResponse (added in RC to replace the generic HttpResponseMessage<T> class that no longer exists) method if you want to pass complex objects:
context.Response = context.Request.CreateResponse(
context.Exception.ConvertToHttpStatus(),
new MyViewModel { Foo = "bar" }
);

Resources