ASP.NET Core 2 - How to call and manipulate a Database class from a controller - asp.net-mvc

I am using ASP.NET Core 2 and I have a controller that runs Tasks.
For example, the one below does a simple file upload, I have others that run other Tasks or Actions and I want to be able to log the events or tasks into my database.
So I need to create a class to run INSERTs or UPDATEs on a database.
How do I create a class that does my database manipulation either using DbContext or call a stored procedure using a class (and not a controller)?
Here is a sample of one of my controller's code:
public async Task<IActionResult> Uploads(string fullName, IFormFile pic)
{
try {
string user = null;
try
{
user = User.Identity.Name.ToString();
}
catch (Exception err)
{
user = "anonymous";
}
if (user == null)
{
user = "";
}
string path = he.WebRootPath + "/uploads/" + user ;
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
DateTime date = DateTime.Now ;
var dates = date.ToLongDateString();
var ext = Path.GetExtension(path).ToLowerInvariant();
var fileName = Path.Combine(he.WebRootPath + "/uploads/" + "/" + user, Path.GetFileName(pic.FileName));
var f = Path.Combine(he.WebRootPath + "/uploads/" + "/" + user, dates+Path.GetFileName(pic.FileName));
int i = 0;
ViewData["fname"] = fullName;
if (pic != null || pic.Length == 0)
{
using (var stream = new FileStream(fileName, FileMode.Create))
{
await pic.CopyToAsync(stream);
}
ViewData["fileLocation"] = "/uploads/" + user + "/" + Path.GetFileName(pic.FileName);
// }
}

You can use dependency injection to inject your DbContext into your controller:
public class MyController : Controller
{
private readonly DbContext _db;
public MyController(DbContext db)
{
_db = db;
}
public async Task<IActionResult> Uploads(string fullName, IFormFile pic)
{
_db.ExecuteSql("INSERT ...");
}
}
Once you have your Db context, you can do what you need with it.

Related

Confusion on getting access token from google api with mvc

I've been trying to follow a number of tutorials I can find to have an mvc application allow a user to authenticate the app and get the access and refresh tokens back. Unfortunately I can't find any that are clear enough to where I can follow what's going on. I started with google's sample code and then found some others like this one and this one.
When I run my app I'm trying to go to http://localhost:61581/Integration/Google/IndexAsync it hits that method which eventually hits the AppFlowMetadata.GetUserId method and then hits my custom TenixDataStore class' GetAsync method.
The things that are confusing are
First off, am I going to the right url/method? I think I am based on google's code example but not sure.
I thought that the key I would get would be the email address but instead is a GUID. Is that how google identifies a user?
If I'm going to the right url, why does the page just hang and never return. I expected it to open a google authorization page which didn't happen.
Here's my code.
AppFlowMetadata class
using System.Web.Mvc;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Mvc;
using Google.Apis.Gmail.v1;
using Tenix.Domain.Constants;
namespace MyApp.Areas.Integration.Controllers
{
public class AppFlowMetadata : FlowMetadata
{
private static readonly IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = APIConstants.GMailApiKey,
ClientSecret = APIConstants.GmailApiSecret
},
Scopes = new[] {GmailService.Scope.GmailReadonly},
DataStore = new TenixDataStore()
});
public override IAuthorizationCodeFlow Flow
{
get { return flow; }
}
public override string GetUserId(Controller controller)
{
// In this sample we use the session to store the user identifiers.
// That's not the best practice, because you should have a logic to identify
// a user. You might want to use "OpenID Connect".
// You can read more about the protocol in the following link:
// https://developers.google.com/accounts/docs/OAuth2Login.
var user = controller.Session["UserID"];
if (user == null) return null;
return user.ToString();
}
}
}
GoogleController
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;
using Google.Apis.Auth.OAuth2.Mvc;
using Google.Apis.Gmail.v1;
using Google.Apis.Services;
namespace MyApp.Areas.Integration.Controllers
{
public class GoogleController : Controller
{
public async Task IndexAsync(CancellationToken cancellationToken)
{
if (Session["UserID"] == null)
{
Response.Redirect("~/Login.aspx", true);
}
var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).AuthorizeAsync(cancellationToken);
if (result.Credential != null)
{
var service = new GmailService(new BaseClientService.Initializer
{
HttpClientInitializer = result.Credential,
ApplicationName = "Tenix Gmail Integration"
});
}
}
}
}
TenixDataStore class
using System;
using System.Threading.Tasks;
using DataBaseUtilitiesTEN;
using Google.Apis.Json;
using Google.Apis.Util.Store;
using Newtonsoft.Json.Linq;
using Synergy.Extensions;
using Tenix.Domain.Data.Respositories;
using Tenix.Domain.Model.Integration;
using Tenix.Domain.Services;
namespace MyApp.Areas.Integration.Controllers
{
public class TenixDataStore : IDataStore
{
private readonly string conStr = ConnectionStrings.GeneralInfo;
private CredentialService _service;
public TenixDataStore()
{
_service = new CredentialService(new CredentialRepository(conStr));
}
public Task StoreAsync<T>(string key, T value)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentException("Key MUST have a value");
var serialized = NewtonsoftJsonSerializer.Instance.Serialize(value);
var jObject = JObject.Parse(serialized);
var access_token = jObject.SelectToken("access_token");
var refresh_token = jObject.SelectToken("refresh_token");
if (access_token == null)
throw new ArgumentException("Missing access token");
if (refresh_token == null)
throw new ArgumentException("Missing refresh token");
_service.SaveUserCredentials(new UserCredential
{
EmailAddress = key,
AccessToken = (string)access_token,
RefreshToken = (string)refresh_token
});
return Task.Delay(0);
}
public Task DeleteAsync<T>(string key)
{
_service.DeleteCredentials(key);
return Task.Delay(0);
}
public Task<T> GetAsync<T>(string userId)
{
var credentials = _service.GetUserCredentials(userId.To<int>());
var completionSource = new TaskCompletionSource<T>();
if (!string.IsNullOrEmpty(credentials.AccessToken))
completionSource.SetResult(NewtonsoftJsonSerializer.Instance.Deserialize<T>(credentials.AccessToken));
return completionSource.Task;
}
public Task ClearAsync()
{
return Task.Delay(0);
}
}
}
AuthCallbackController
using Google.Apis.Auth.OAuth2.Mvc;
namespace MyApp.Areas.Integration.Controllers
{
public class AuthCallbackController : Google.Apis.Auth.OAuth2.Mvc.Controllers.AuthCallbackController
{
protected override FlowMetadata FlowData
{
get { return new AppFlowMetadata(); }
}
}
}
After spending days trying to figure this out and not making any headway with the google api .net libraries I ended up just going with my own implementation which after reading their documentation was at least something I could fully understand. In case anyone could use the code, here's what I ended up with. Still need to do some refactoring, but at this point it's working.
Just need to make sure the AuthorizeResponse and Authorize routes are registered as authorized redirect uris.
public class GoogleController : Controller
{
private readonly CredentialService _credentialService;
private readonly GoogleEndpoints _endpoints;
public GoogleController()
{
_endpoints = new GoogleEndpoints();
_credentialService = new CredentialService(new CredentialRepository(ConnectionStrings.GeneralInfo));
}
private string AuthorizeUrl
{
get
{
return "/Integration/Google/Authorize";
}
}
private string AuthorizeResponseUrl
{
get
{
return "/Integration/Google/AuthorizeResponse";
}
}
private string SaveResponseUrl
{
get
{
return "/Integration/Google/SaveResponse";
}
}
public void Authorize()
{
if (Session["UserID"] == null || Session["Email"] == null)
{
Response.Redirect("~/Login.aspx", true);
Session["LoginSource"] = AuthorizeUrl;
Response.End();
}
else
{
if (Session["SessionId"] == null || Session["SessionId"].ToString().Trim().Length == 0)
Session["SessionId"] = _credentialService.CreateSessionId(Session["UserID"].To<int>());
var url = _endpoints.AuthorizationEndpoint + "?" +
"client_id=" + APIConstants.GMailApiKey + "&" +
"response_type=code&" +
"scope=openid%20email&" +
"redirect_uri=" + AuthorizeResponseUrl + "&" +
"state=" + Session["SessionId"] + "&" +
"login_hint=" + Session["Email"] + "&" +
"access_type=offline";
Response.Redirect(url);
}
}
public ActionResult AuthorizeResponse()
{
var state = Request.QueryString["state"];
if (state == Session["SessionId"].ToString())
{
var code = Request.QueryString["code"];
var values = new Dictionary<string, object>
{
{"code", code},
{"redirect_uri", AuthorizeResponseUrl},
{"client_id", APIConstants.GMailApiKey},
{"client_secret", APIConstants.GmailApiSecret},
{"grant_type", "authorization_code"},
{"scope", ""}
};
var webmethods = new WebMethods();
var tokenResponse = webmethods.Post(_endpoints.TokenEndpoint, values);
var jobject = JObject.Parse(tokenResponse);
var access_token = jobject.SelectToken("access_token");
var refresh_token = jobject.SelectToken("refresh_token");
if (access_token == null || access_token.ToString().Trim().Length == 0)
{
//notify devs something went wrong
return View(new GoogleAuthResponse(tokenResponse, false));
}
var credentials = _credentialService.GetUserCredentials(Session["SessionId"].ToString());
credentials.AccessToken = access_token.ToString();
credentials.RefreshToken = refresh_token.ToString();
credentials.EmployeeId = Session["UserId"].To<int>();
_credentialService.SaveUserCredentials(credentials);
return View(new GoogleAuthResponse("Integration successful!", true));
}
return View(new GoogleAuthResponse("Missing state information.", false));
}
}
And the helper class to get the google endpoints.
public class GoogleEndpoints
{
public GoogleEndpoints()
{
using (var client = new WebClient())
{
var response = client.DownloadString("https://accounts.google.com/.well-known/openid-configuration");
var jobject = JObject.Parse(response);
AuthorizationEndpoint = jobject.SelectToken("authorization_endpoint").ToString();
TokenEndpoint = jobject.SelectToken("token_endpoint").ToString();
}
}
public string AuthorizationEndpoint { get; private set; }
public string TokenEndpoint { get; private set; }
}
The controller uses another couple of helper classes for parsing the json and posting the form data, but that should be pretty straightforward.

Serilog stops logging events

I have created a Serilog sink that talks to a web service which persists log messages to a database. It works most of the time. Even in cases where there is an exception calling the web service it will log to the Selflog file. However, However, periodically it simply stops logging either to our custom web service or to the self log file and after it stops logging it never begins logging anywhere else. This is being executed in a windows service and I have to stop and restart the windows service before it begins logging again. A typical exception that i might get from the web service call is: "Task was cancelled". This would be caused because the webservice does not respond within the configured timeout period. As I said normally it will properly write the events to the selflog file. Only periodically will it just stop logging everywhere. I should also say that the volume of logs being generated is very high.
This is a dnx project and here is a portion of the project.json file:
"dependencies": {
"Newtonsoft.Json": "8.0.2",
"Serilog.Sinks.PeriodicBatching": "2.0.0",
"Serilog": "2.0.0-beta-465",
"Serilog.Extensions.Logging": "1.0.0-rc1-final-10092",
"JA.AppCentral.Logging.Contracts": "0.1.0-alpha1-*",
"FluentAssertions": "4.2.2",
"Microsoft.Extensions.Configuration": "1.0.0-rc1-final",
"Microsoft.AspNet.WebApi.Client": "4.0.30506"
}
I have included relevant portions of the sink class. It inherits from periodic batching sink.
The code used to configure the Selflog follows:
FileStream fs = new FileStream(selfLogFilePath, fileMode, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);
Serilog.Debugging.SelfLog.Out = TextWriter.Synchronized(sw);
Here is the sink code:enter code here
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Serilog;
using System.Net.Http;
using Serilog.Core;
using Serilog.Events;
using System.Net.Http.Headers;
using System.IO;
using Serilog.Formatting.Json;
using Serilog.Debugging;
using Newtonsoft.Json;
using JA.AppCentral.Logging.Contracts;
using Microsoft.Extensions.Configuration;
using Serilog.Sinks.PeriodicBatching;
using System.Diagnostics;
using System.Threading;
namespace JA.AppCentral.Logging
{
public class AppCentralSink: Serilog.Sinks.PeriodicBatching.PeriodicBatchingSink
{
readonly HttpClient _httpClient;
LoggingLevelSwitch _levelControlSwitch;
const string BulkAddUri = "api/appLogging/bulkAdd";
private Uri _baseUri;
private string _baseUriPath;
readonly long? _eventBodyLimitBytes = 1000000;
static readonly TimeSpan RequiredLevelCheckInterval = TimeSpan.FromSeconds(10);
private TimeSpan _timeout = TimeSpan.FromMinutes(1);
private bool _saveMessageTemplate;
private int eventsCount;
private LoggingRepositoryServiceResponse _logServiceResponse;
private int _totalInsertedRecords;
public event EventHandler<ResponseEventArgs> ResponseReceived = delegate { };
DateTime _nextRequiredLevelCheckUtc = DateTime.Now.Add(RequiredLevelCheckInterval);
private int osId;
private string server;
private string username;
private int threadId;
private string appcode;
/// <summary>
/// Overloaded constructor, to pass AppSettings via IConfiguration , instead of separate parameters
/// </summary>
/// <param name="config"></param>
public AppCentralSink(IConfiguration config)
: base(Convert.ToInt32(GetConfigParams(config)["BatchSizeLimit"]),
TimeSpan.FromSeconds(Convert.ToDouble(GetConfigParams(config)["BatchEmitIntervalSeconds"])))
{
Dictionary<string, string> appSettingDict = GetConfigParams(config);
long tempLongVal;
long? eventBodyLimitBytes = long.TryParse(appSettingDict["EventBodyMaxSizeBytes"], out tempLongVal) ? tempLongVal : (long?)null;
if (eventBodyLimitBytes != null)
_eventBodyLimitBytes = eventBodyLimitBytes;
bool saveMessageTemplate = Convert.ToBoolean(appSettingDict["LogMessageTemplate"]);
if (saveMessageTemplate != false)
_saveMessageTemplate = saveMessageTemplate;
string serverUrl = appSettingDict["Url"];
//baseUri = "http://localhost:49774/";
if (!serverUrl.EndsWith("/"))
serverUrl += "/";
_baseUriPath = serverUrl;
_baseUri = new Uri(serverUrl);
TimeSpan timeout = TimeSpan.FromSeconds(Convert.ToDouble(appSettingDict["WebRequestTimeoutSeconds"]));
if (timeout != default(TimeSpan))
_timeout = timeout;
//Default Authentication via http client handler
HttpClientHandler handler = new HttpClientHandler()
{
PreAuthenticate = true,
UseDefaultCredentials = true
};
_httpClient = new HttpClient(handler);
_httpClient.BaseAddress = _baseUri;
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_httpClient.Timeout = _timeout;
//Init Context properties
OsId = Process.GetCurrentProcess().Id;
Server = Environment.MachineName;
Username = Environment.UserName;
ThreadId = Thread.CurrentThread.ManagedThreadId;
Appcode = config["JA:AppCatalog:AppCode"];
}
private static Dictionary<string,string> GetConfigParams(IConfiguration config)
{
Dictionary<string, string> appSettings = new Dictionary<string, string>();
var SerilogSection = config.GetSection("AppCentralLogging");
appSettings.Add("Url", SerilogSection["Url"]);
appSettings.Add("BatchSizeLimit", SerilogSection["BatchSizeLimit"]);
appSettings.Add("BatchEmitIntervalSeconds", SerilogSection["BatchEmitIntervalSeconds"]);
appSettings.Add("EventBodyMaxSizeBytes", SerilogSection["EventBodyMaxSizeBytes"]);
appSettings.Add("LogMessageTemplate", SerilogSection["LogMessageTemplate"]);
appSettings.Add("WebRequestTimeoutSeconds", SerilogSection["WebRequestTimeoutSeconds"]);
appSettings.Add("SelfLogFileLocationAndPrefix", config["Serilog:SelfLogFileLocationAndPrefix"]);
return appSettings;
}
// The sink must emit at least one event on startup, and the server be
// configured to set a specific level, before background level checks will be performed.
protected override void OnEmptyBatch()
{
if (_levelControlSwitch != null &&
_nextRequiredLevelCheckUtc < DateTime.Now)
{
EmitBatch(Enumerable.Empty<LogEvent>());
}
}
protected override async Task EmitBatchAsync(IEnumerable<LogEvent> events)
{
_nextRequiredLevelCheckUtc = DateTime.Now.Add(RequiredLevelCheckInterval);
var formatter = new JsonFormatter();
List<LogEntry> logEntriesList = new List<LogEntry>();
try
{
foreach (var logEvent in events)
{
EventsCount++;
LogEntry jaLogEvent = ConvertToLogEntry(logEvent);
if (_eventBodyLimitBytes.HasValue)
{
var scratch = new StringWriter();
formatter.Format(logEvent, scratch);
var buffered = scratch.ToString();
if (Encoding.UTF8.GetByteCount(buffered) > _eventBodyLimitBytes.Value)
{
SelfLog.WriteLine("Event JSON representation exceeds the byte size limit of {0} set for this sink and will be dropped; data: {1}", _eventBodyLimitBytes, buffered);
}
else
{
logEntriesList.Add(jaLogEvent);
}
}
else
{
logEntriesList.Add(jaLogEvent);
}
}
var result = await _httpClient.PostAsJsonAsync(BulkAddUri, logEntriesList);
if (!result.IsSuccessStatusCode)
{
try
{
var error = await result.Content.ReadAsStringAsync();
var responseExcep = new Exception(error);
throw responseExcep;
}
catch (Exception e)
{
SelfLog.WriteLine("FailedEvents: " + GetEventsAsString(events));
throw new Exception("Error calling Logging Web Service: status code: " + result.StatusCode +
" reason: " + result.ReasonPhrase + " excep: " + e.ToString());
}
}
_logServiceResponse = await result.Content.ReadAsAsync<LoggingRepositoryServiceResponse>();
if (_logServiceResponse.ResponseException != null)
{
SelfLog.WriteLine("FailedEvents: " + GetEventsAsString(events));
SelfLog.WriteLine(_logServiceResponse.ResponseMessage);
throw new Exception("Error calling Logging Web Service: " +
_logServiceResponse.ResponseMessage);
}
_totalInsertedRecords = _totalInsertedRecords + _logServiceResponse.NumRecordsInserted;
ResponseReceived(this, new ResponseEventArgs(result));
}
catch (Exception e)
{
SelfLog.WriteLine("Error processing log batch, excep: " + e.ToString());
SelfLogEvents(events);
throw;
}
}
private void SelfLogEvents(IEnumerable<LogEvent> events)
{
SelfLog.WriteLine("Failed to write following log events:");
foreach (var e in events)
{
SelfLog.WriteLine($" Event: " + e.RenderMessage());
}
}
private string GetEventsAsString(IEnumerable<LogEvent> events)
{
string eventsResult = string.Empty;
foreach(LogEvent le in events)
{
eventsResult += "[" + le.RenderMessage() + "]";
}
return eventsResult;
}
private LogEntry ConvertToLogEntry(LogEvent logEvent)
{
string propertiesString = JsonConvert.SerializeObject(logEvent.Properties);
string messageTemplate = _saveMessageTemplate == true ? logEvent.MessageTemplate.Text : string.Empty;
//Append Exception to the message if it's not null
string logEventMessage = logEvent.RenderMessage();
if (logEvent.Exception != null)
{
logEventMessage = logEventMessage + " Exception: " + logEvent.Exception.ToString();
}
LogEntry logEntry = new LogEntry("AppCode", "Action", logEvent.Level.ToString(), messageTemplate,
logEventMessage, propertiesString,
logEvent.Timestamp);
//Append additional properties
if (String.IsNullOrEmpty(Appcode))
{
logEntry.AppCode = logEvent.Properties.Keys.Contains("appcode") ? logEvent.Properties["appcode"].ToString().Replace("\"", "") : string.Empty;
logEntry.OsPId = logEvent.Properties.Keys.Contains("os_pid") ? logEvent.Properties["os_pid"].ToString().Replace("\"", "") : string.Empty;
logEntry.ThreadId = logEvent.Properties.Keys.Contains("thread_id") ? logEvent.Properties["thread_id"].ToString().Replace("\"", "") : string.Empty;
logEntry.Server = logEvent.Properties.Keys.Contains("server") ? logEvent.Properties["server"].ToString().Replace("\"", "") : string.Empty;
logEntry.Username = logEvent.Properties.Keys.Contains("username") ? logEvent.Properties["username"].ToString().Replace("\"", "") : string.Empty;
}
else
{
logEntry.AppCode = Appcode;
logEntry.OsPId = OsId.ToString();
logEntry.ThreadId = ThreadId.ToString();
logEntry.Server = Server;
logEntry.Username = Username;
}
logEntry.SessionId = logEvent.Properties.Keys.Contains("session_id") ? logEvent.Properties["session_id"].ToString().Replace("\"", "") : string.Empty;
logEntry.Action = logEvent.Properties.Keys.Contains("action") ? logEvent.Properties["action"].ToString().Replace("\"", "") : string.Empty;
//Append SourceContext
//Append SourceContext
LogEventPropertyValue propertyValue;
if (logEvent.Properties.TryGetValue("SourceContext", out propertyValue))
{
logEntry.SourceContext = propertyValue.ToString().Trim(new[] { '"' });
}
return logEntry;
}
public int EventsCount
{
get
{
return eventsCount;
}
set
{
eventsCount = value;
}
}
public LoggingRepositoryServiceResponse LogServiceResponse
{
get
{
return _logServiceResponse;
}
set
{
_logServiceResponse = value;
}
}
public int TotalInsertedRecords
{
get
{
return _totalInsertedRecords;
}
set
{
_totalInsertedRecords = value;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
_httpClient.Dispose();
}
public HttpClient HttpClient
{
get { return _httpClient; }
}
}
public class ResponseEventArgs : EventArgs
{
public ResponseEventArgs(HttpResponseMessage response)
{
Response = response;
}
public HttpResponseMessage Response { get; }
}
}

Call WCF Restful POST Method in MVC 5

I have to create simple WCF web service with GET and POST. See bellow source code
public interface ISample
{
[OperationContract]
[WebGet(UriTemplate = "/GetDEPT", RequestFormat = WebMessageFormat.Json,ResponseFormat = WebMessageFormat.Json)]
Task<IEnumerable<DEPT>> GetDEPT();
[OperationContract]
[WebInvoke(UriTemplate = "UpdateDEPT?Id={Id}&StatusId={StatusId}", Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
Task<bool> UpdateDEPT(List<DEPT> DEPT, string Id, string StatusId);
}
ISample interface Implementation : Sample
public class Sample: ISample
{
public async Task<IEnumerable<DEPTt>> GetDEPT()
{
return await DEPTBO.GetDEPT();
}
public async Task<bool> UpdateDEPT(List<DEPTt> DEPT, string Id, string StatusId)
{
return await DEPTBO.UpdateDEPTAsync(Id, DEPT, StatusId);
}
}
How to call this WCF Restful service in MVC 5?
Please help me Service integration in MVC Application
Now i found the solution for my question.
I have create class for proxy
namespace WCF.WCFService
{
public static class WebService<T> where T : class
{
public static string appSettings = ConfigurationManager.AppSettings["ServiceURL"];
public static IEnumerable<T> GetDataFromService(string Method, string param = "")
{
var client = new WebClient();
var data = client.DownloadData(appSettings + Method + param);
var stream = new System.IO.MemoryStream(data);
var obj = new DataContractJsonSerializer(typeof(IEnumerable<T>));
var result = obj.ReadObject(stream);
IEnumerable<T> Ts = (IEnumerable<T>)result;
return Ts;
}
}
public static class WebServiceUpdate
{
public static string appSettings = ConfigurationManager.AppSettings["ServiceURL"];
public static bool GetDataFromService_Update(string Method, List<CNHDataModel.CustomEntities.Port> portData, string param = "")
{
bool _res = false;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<CNHDataModel.CustomEntities.Port>));
MemoryStream mem = new MemoryStream();
serializer.WriteObject(mem, portData);
string data =
Encoding.UTF8.GetString(mem.ToArray(), 0, (int)mem.Length);
WebClient webClient = new WebClient();
webClient.Headers["Content-type"] = "application/json";
webClient.Encoding = Encoding.UTF8;
webClient.UploadString(appSettings + Method + param, "POST", data);
_res = true;
bool Ts = (bool)_res;
return Ts;
}
}
}
Bellow, call the service proxy from controller
public class DEPTController : Controller
{
[ActionName("DEPTView")]
public ActionResult DEPTViewAsync()
{
try
{
IEnumerable<DEPT> DEPT = CNHService.WebService<DEPT>.GetDataFromService("GetDEPT");
if (port == null)
{
return HttpNotFound();
}
IEnumerable<Status> Status = CNHService.WebService<Status>.GetDataFromService("GetStatusAsync");
if (port == null || Status == null)
{
return HttpNotFound();
}
}
catch (Exception ex)
{
}
return View();
}
[HttpPost]
[ActionName("DEPTView")]
public ActionResult DEPTViewAsync([Bind(Include = "id,Statusid")] DEPT DEPTMENT)
{
try
{
List<DEPT> objDEPT = Session["DEPTItems"] as List<DEPT>;
List<DEPTStatus> objStatus = Session["DEPTIStatus"] as List<PortStatus>;
ViewBag.DEPTList = new SelectList(objDEPTt, "id", "Name");
ViewBag.DEPTStatusList = new SelectList(objStatus, "id", "Name");
if (ModelState.IsValid)
{
WebServiceUpdate.GetDataFromService_Update("UpdateDEPT", objDEPT, "?Id=" + DEPTMENT.Id + "&StatusId=" + DEPTMENT.Statusid);
setting.Message = true;
}
else
{
return View(setting);
}
}
catch (Exception ex)
{
}
return View(setting);
}
}
I hope this code help to WCF Restful service integration in MVC 5

How would I mimic User.IsInRole()

I have a website thats build with VS 2012 Internet Application ( Simple membership) EF Code First
Updates
I would like to know how to extend HttpContext.User.IsInRole(role) 's functionality for a custom table -> User.IsInClient(client).
Here is the way I'd suggest to solve your issue:
Create your own interface which implements System.Security.Principal, where you could place any methods you need:
public interface ICustomPrincipal : IPrincipal
{
bool IsInClient(string client);
}
Implement this interface:
public class CustomPrincipal : ICustomPrincipal
{
private readonly IPrincipal _principal;
public CustomPrincipal(IPrincipal principal) { _principal = principal; }
public IIdentity Identity { get { return _principal.Identity; } }
public bool IsInRole(string role) { return _principal.IsInRole(role); }
public bool IsInClient(string client)
{
return _principal.Identity.IsAuthenticated
&& GetClientsForUser(_principal.Identity.Name).Contains(client);
}
private IEnumerable<string> GetClientsForUser(string username)
{
using (var db = new YourContext())
{
var user = db.Users.SingleOrDefault(x => x.Name == username);
return user != null
? user.Clients.Select(x => x.Name).ToArray()
: new string[0];
}
}
}
In the Global.asax.cs assign your custom principal to the request user context (and optionally to the executing thread if you plan to use it later). I suggest to use Application_PostAuthenticateRequest event not Application_AuthenticateRequest for this assignment, otherwise your principal will be overridden (at least by ASP.NET MVC 4):
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
Context.User = Thread.CurrentPrincipal = new CustomPrincipal(User);
/*
* BTW: Here you could deserialize information you've stored earlier in the
* cookie of authenticated user. It would be helpful if you'd like to avoid
* redundant database queries, for some user-constant information, like roles
* or (in your case) user related clients. Just sample code:
*
* var authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
* var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
* var cookieData = serializer.Deserialize<CookieData>(authCookie.UserData);
*
* Next, pass some deserialized data to your principal:
*
* Context.User = new CustomPrincipal(User, cookieData.clients);
*
* Obviously such data have to be available in the cookie. It should be stored
* there after you've successfully authenticated, e.g. in your logon action:
*
* if (Membership.ValidateUser(user, password))
* {
* var cookieData = new CookieData{...};
* var userData = serializer.Serialize(cookieData);
*
* var authTicket = new FormsAuthenticationTicket(
* 1,
* email,
* DateTime.Now,
* DateTime.Now.AddMinutes(15),
* false,
* userData);
*
* var authTicket = FormsAuthentication.Encrypt(authTicket);
* var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName,
authTicket);
* Response.Cookies.Add(authCookie);
* return RedirectToAction("Index", "Home");
* }
*/
}
Next, to be able to use the property User from HttpContext in the controller without casting it to ICustomPrincipal each time, define base controller where you override the default User property:
public class BaseController : Controller
{
protected virtual new ICustomPrincipal User
{
get { return (ICustomPrincipal)base.User; }
}
}
Now, let other controllers inherit from it:
public class HomeController : BaseController
{
public ActionResult Index()
{
var x = User.IsInClient(name);
If you use Razor View Engine, and you'd like to be able to use your method in the very similar way on the views:
#User.IsInClient(name)
you need to redefine WebViewPage type:
public abstract class BaseViewPage : WebViewPage
{
public virtual new ICustomPrincipal User
{
get { return (ICustomPrincipal)base.User; }
}
}
public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
public virtual new ICustomPrincipal User
{
get { return (ICustomPrincipal)base.User; }
}
}
and tell Razor to reflect you changes, by modifying appropriate section of the Views\Web.config file:
<system.web.webPages.razor>
...
<pages pageBaseType="YourNamespace.BaseViewPage">
Use Linq:
var Users = Membership.GetAllUsers();
//**Kinda Like Users.InCLients(userName).
var users = from x in Users
join y in db.Clinets on x.ProviderUserKey equals y.UserID
select x
//**Kinda Like Clients.InUsers(userName)
var clients = from x in db.Clinets
join y in Users on x.UserID equals y.ProviderUserKey
select x
try this way
List<Clinets> AllClinets =entityObject.Clinets .ToList();
Foreach( var check in AllClinets)
{
if(check.UserTable.RoleTable.RoleName=="Rolename1")
{
//This users are Rolename1
}
else
{
//other.
}
}
Stored procedure would be better in this case.

Rendering an RDLC report in HTML in ASP.NET MVC

I would like to render an RDLC report in HTML within an ASP.NET MVC project.
I successfully made a prototype that renders an RDLC report in PDF, Excel, and TIFF image, with the help of this article. But I was surprised that HTML is not one of the default available formats in LocalReport.Render().
I came across this article, which describes a trick to enable the rendering format of HTML4.0, but I think that is only for a ReportViewer control (I could be wrong though).
The question is, in MVC how to render an RDLC report in HTML just like a ReportView does (see the screenshot below)?
This is a simple task. You can follow the following steps.
Create a folder in your solution and give a name Reports.
Add a ASP.Net web form and named it ReportView.aspx
Create a Class ReportData and add it to the Reports folder. Add the following code
to the Class.
public class ReportData
{
public ReportData()
{
this.ReportParameters = new List<Parameter>();
this.DataParameters = new List<Parameter>();
}
public bool IsLocal { get; set; }
public string ReportName { get; set; }
public List<Parameter> ReportParameters { get; set; }
public List<Parameter> DataParameters { get; set; }
}
public class Parameter
{
public string ParameterName { get; set; }
public string Value { get; set; }
}
Add another Class and named it ReportBasePage.cs. Add the following code in this Class.
public class ReportBasePage : System.Web.UI.Page
{
protected ReportData ReportDataObj { get; set; }
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (HttpContext.Current != null)
if (HttpContext.Current.Session["ReportData"] != null)
{
ReportDataObj = HttpContext.Current.Session["ReportData"] as ReportData;
return;
}
ReportDataObj = new ReportData();
CaptureRouteData(Page.Request);
}
private void CaptureRouteData(HttpRequest request)
{
var mode = (request.QueryString["rptmode"] + "").Trim();
ReportDataObj.IsLocal = mode == "local" ? true : false;
ReportDataObj.ReportName = request.QueryString["reportname"] + "";
string dquerystr = request.QueryString["parameters"] + "";
if (!String.IsNullOrEmpty(dquerystr.Trim()))
{
var param1 = dquerystr.Split(',');
foreach (string pm in param1)
{
var rp = new Parameter();
var kd = pm.Split('=');
if (kd[0].Substring(0, 2) == "rp")
{
rp.ParameterName = kd[0].Replace("rp", "");
if (kd.Length > 1) rp.Value = kd[1];
ReportDataObj.ReportParameters.Add(rp);
}
else if (kd[0].Substring(0, 2) == "dp")
{
rp.ParameterName = kd[0].Replace("dp", "");
if (kd.Length > 1) rp.Value = kd[1];
ReportDataObj.DataParameters.Add(rp);
}
}
}
}
}
Add ScriptManager to the ReportView.aspx page. Now Take a Report Viewer to the page. In report viewer set the property AsyncRendering="false". The code is given below.
<rsweb:ReportViewer ID="ReportViewerRSFReports" runat="server" AsyncRendering="false"
Width="1271px" Height="1000px" >
</rsweb:ReportViewer>
Add two NameSpace in ReportView.aspx.cs
using Microsoft.Reporting.WebForms;
using System.IO;
Change the System.Web.UI.Page to ReportBasePage. Just replace your code using the following.
public partial class ReportView : ReportBasePage
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
RenderReportModels(this.ReportDataObj);
}
}
private void RenderReportModels(ReportData reportData)
{
RASolarERPData dal = new RASolarERPData();
List<ClosingInventoryValuation> objClosingInventory = new List<ClosingInventoryValuation>();
// Reset report properties.
ReportViewerRSFReports.Height = Unit.Parse("100%");
ReportViewerRSFReports.Width = Unit.Parse("100%");
ReportViewerRSFReports.CssClass = "table";
// Clear out any previous datasources.
this.ReportViewerRSFReports.LocalReport.DataSources.Clear();
// Set report mode for local processing.
ReportViewerRSFReports.ProcessingMode = ProcessingMode.Local;
// Validate report source.
var rptPath = Server.MapPath(#"./Report/" + reportData.ReportName +".rdlc");
//#"E:\RSFERP_SourceCode\RASolarERP\RASolarERP\Reports\Report\" + reportData.ReportName + ".rdlc";
//Server.MapPath(#"./Report/ClosingInventory.rdlc");
if (!File.Exists(rptPath))
return;
// Set report path.
this.ReportViewerRSFReports.LocalReport.ReportPath = rptPath;
// Set report parameters.
var rpPms = ReportViewerRSFReports.LocalReport.GetParameters();
foreach (var rpm in rpPms)
{
var p = reportData.ReportParameters.SingleOrDefault(o => o.ParameterName.ToLower() == rpm.Name.ToLower());
if (p != null)
{
ReportParameter rp = new ReportParameter(rpm.Name, p.Value);
ReportViewerRSFReports.LocalReport.SetParameters(rp);
}
}
//Set data paramater for report SP execution
objClosingInventory = dal.ClosingInventoryReport(this.ReportDataObj.DataParameters[0].Value);
// Load the dataSource.
var dsmems = ReportViewerRSFReports.LocalReport.GetDataSourceNames();
ReportViewerRSFReports.LocalReport.DataSources.Add(new ReportDataSource(dsmems[0], objClosingInventory));
// Refresh the ReportViewer.
ReportViewerRSFReports.LocalReport.Refresh();
}
}
Add a Folder to the Reports Folder and named it Report. Now add a RDLC report to the Reports/Report folder and named it ClosingInventory.rdlc.
Now add a Controller and Named it ReportController. In to the controller add the following action method.
public ActionResult ReportViewer()
{
ViewData["reportUrl"] = "../Reports/View/local/ClosingInventory/";
return View();
}
Add a view page click on the ReportViewer Controller. Named the view page ReportViewer.cshtml. Add the following code to the view page.
#using (Html.BeginForm("Login"))
{
#Html.DropDownList("ddlYearMonthFormat", new SelectList(ViewBag.YearMonthFormat, "YearMonthValue", "YearMonthName"), new { #class = "DropDown" })
Stock In Transit: #Html.TextBox("txtStockInTransit", "", new { #class = "LogInTextBox" })
<input type="submit" onclick="return ReportValidationCheck();" name="ShowReport"
value="Show Report" />
}
Add an Iframe. Set the property of the Iframe as follows
frameborder="0" width="1000"; height="1000"; style="overflow:hidden;" scrolling="no"
Add Following JavaScript to the viewer.
function ReportValidationCheck() {
var url = $('#hdUrl').val();
var yearmonth = $('#ddlYearMonthFormat').val();
var stockInTransit = $('#txtStockInTransit').val()
if (stockInTransit == "") {
stockInTransit = 0;
}
if (yearmonth == "0") {
alert("Please Select Month Correctly.");
}
else {
//url = url + "dpSpYearMonth=" + yearmonth + ",rpYearMonth=" + yearmonth + ",rpStockInTransit=" + stockInTransit;
url = "../Reports/ReportView.aspx?rptmode=local&reportname=ClosingInventory&parameters=dpSpYearMonth=" + yearmonth + ",rpYearMonth=" + yearmonth + ",rpStockInTransit=" + stockInTransit;
var myframe = document.getElementById("ifrmReportViewer");
if (myframe !== null) {
if (myframe.src) {
myframe.src = url;
}
else if (myframe.contentWindow !== null && myframe.contentWindow.location !== null) {
myframe.contentWindow.location = url;
}
else { myframe.setAttribute('src', url); }
}
}
return false;
}
In Web.config file add the following key to the appSettings section add
key="UnobtrusiveJavaScriptEnabled" value="true"
In system.web handlers Section add the following key
add verb="*" path="Reserved.ReportViewerWebControl.axd" type = "Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Change your data source as your own. This solution is very simple and I think every one enjoy it.
You can use the ReportViewer object to render an RDLC to PDF or HTML. For my case (below) I wanted a PDF document and I returned it as a FileContentResult ActionResult. If you want it to return as a download use the File ActionResult (I've commented that out for your use).
public ActionResult GetPackingSlipPDF(int shipmentId)
{
var shipment = _inboundShipmentService.GetInboundShipmentById(shipmentId);
Warning[] warnings;
string mimeType;
string[] streamids;
string encoding;
string filenameExtension;
var viewer = new ReportViewer();
viewer.LocalReport.ReportPath = #"Labels\PackingSlip.rdlc";
var shipLabel = new ShippingLabel { ShipmentId = shipment.FBAShipmentId, Barcode = GetBarcode(shipment.FBAShipmentId) };
viewer.LocalReport.DataSources.Add(new ReportDataSource("ShippingLabel", new List<ShippingLabel> { shipLabel }));
viewer.LocalReport.Refresh();
var bytes = viewer.LocalReport.Render("PDF", null, out mimeType, out encoding, out filenameExtension, out streamids, out warnings);
return new FileContentResult(bytes, mimeType);
//return File(bytes, mimeType, shipment.FBAShipmentId + "_PackingSlip.pdf");
}

Resources